简单手写实现函数组件的Ref - forwardRef

简介: 简单手写实现函数组件的Ref - forwardRef

简单手写实现函数组件的Ref - forwardRef


继续学习写源码系列,本系列是学习系列。

  1. 简单手写实现 React 的 createElement 和 render,里面有准备工作,不再赘述。
  2. 简单手写实现 react 的函数组件
  3. 简单手写实现 react 的类组件
  4. 简单手写实现 React 类组件的 state 更新
  5. 简单手写实现 React 类组件的 state 批量更新
  6. 简单手写实现元素的 Ref
  7. 简单手写实现类组件的 Ref

本文的目标是,手写实现函数的Ref,函数组件需要借助 forwardRef

TL;DR

  • 函数组件用ref的话,需要另外裹下forwardRef
  • forwardRef其实就是将函数组件增加一个ref参数,然后解析的时候,传到组件里,从而进行赋值
  • forwardRef是一种新的type,需要增加新的解析方法。为了区分函数组件,将其加个type属性

准备工作

先将index.js的点击事件略微修改

// import React from './source/react';
// import ReactDOM from './source/react-dom';
import React from 'react';
import ReactDOM from 'react-dom';
const TextInput = React.forwardRef((props, ref) => <input ref={ref} />);
class Form extends React.Component {
  constructor(props) {
    super(props);
    this.textInputRef = React.createRef();
  }
  getFocus = () => {
    console.log(this.textInputRef.current);
    this.textInputRef.current.focus();
  };
  render() {
    return (
      <>
        <TextInput ref={this.textInputRef} />
        <button onClick={this.getFocus}>获得焦点</button>
      </>
    );
  }
}
ReactDOM.render(<Form />, document.getElementById('root'));

点击获得焦点,输入框获得焦点:

网络异常,图片无法展示
|

分析 ref

  1. <TextInput ref={this.textInputRef} />其实本质是借助forwardRefthis.textInputRef赋值为TextInputinput的 DOM
  2. 此处就是难点,本身函数组件并不好赋值 ref,这边将本身的函数组件,再次切片,从而将利用参数,将 ref 引用带到组件里,组件里自动赋值,从而外围拿到函数组件内部的 ref。
  3. 因为包裹了一层 forwardRef,所以这边多增加一个类型,只有被包裹的函数组件,才有获取 ref 值

实现

1.增加 forwardRef

本文为了区分普通函数组件,将forwardRef(fnCp)称为转发的函数组件。

forwardRef 入参是函数,此函数其实就是组件函数,但多一个 ref 参数 forward 返回值返回该函数,但为了区分函数组件和转发的函数组件,所以额外加个 type。

// react.js
// fn是个函数,长得这样(props,ref)=>(<input ref={ref}/>),这里的ref就是例子的textInputRef
const forwardRef = (fn) => {
  fn.type = 'isFunctionForward';
  return fn;
};

解析转发的函数组件

  • type,增加一种,转发的函数组件类型
  • 解析的时候,增加转发的函数组件类型,例子的textInputRef在这时候传过去的
// react-dom.js
// type增加
const getType = (vdom) => {
  const isFn = isObject && typeof vdom.type === 'function';
  if (isFn) {
    if (vdom.type.isFunctionForward) {
      return 'functionForward';
    }
    if (vdom.type.isClassComponent) {
      return 'class';
    }
    return 'function';
  }
}
// 3.1 {type:forward((props,ref)=>()),props:{ref:..}},props有ref,返回值才是vdom
// 和函数组件相比,就是多了ref,也是此处将ref传过去的
const handleFunctionForwardType = (vdom) => {
  const { type: fn, props,ref } = vdom;
  const vdomReturn = fn(props,ref);
  return createElementDOM(vdomReturn);
};
const typeMap = new Map([
  ['text', handleTextType],
  ['element', handleElementType],
  ['function', handleFunctionType],
  ['functionForward', handleFunctionForwardType],
  ['class', handleClassType],
]);

老规矩,index.js打开自己文件的路径

正常运行,✌️~~~

目录
相关文章
|
2天前
|
前端开发 JavaScript API
第八章 react组件实例中三大属性之ref
第八章 react组件实例中三大属性之ref
|
1天前
|
JavaScript
Vue 创建自定义 ref 函数
Vue 创建自定义 ref 函数
|
5月前
【Vue2.0】—ref属性(十四)
【Vue2.0】—ref属性(十四)
|
9月前
|
前端开发 JavaScript
React中Refs的作用是什么?如何使用,父组件是函数组件ref如何获取子组件内容
React中Refs的作用是什么?如何使用,父组件是函数组件ref如何获取子组件内容
157 0
|
10月前
|
存储 JavaScript
如何使用 ref 属性获取子组件实例对象?
如何使用 ref 属性获取子组件实例对象?
79 0
|
11月前
|
JavaScript 前端开发 API
Vue3 —— 常用 Composition API(零)(setup函数、ref函数、reactive函数、响应式、reactive对比ref)
Vue3 —— 常用 Composition API(零)(setup函数、ref函数、reactive函数、响应式、reactive对比ref)
|
JavaScript
Vue3中的ref如何使用?v-for中如何使用?
前言 虽然在 Vue 中不提倡我们直接操作 DOM,毕竟 Vue 的理念是以数据驱动视图。但是在实际情况中,我们有很多需求都是需要直接操作 DOM 节点的,这个时候 Vue 提供了一种方式让我们可以获取 DOM 节点:ref 属性。ref 属性是 Vue2 和 Vue3 中都有的,但是使用方式却不大一样,这也导致了很多从 Vue2 转到 Vue3 的小伙伴感到有些困惑。 今天我们就来揭开 Vue3 中 ref 的神秘面纱!
2131 0
Vue3中的ref如何使用?v-for中如何使用?
|
JavaScript
vue ref获取实例子undefined
当你再created中使用 this.$refs时 dom没有加载成功 所以为undefined 所以你要是想获取 1、要么写在mounted中 dom已经加载完成 2、使用this.$nextTick(function(){})
135 0
vue ref获取实例子undefined
|
前端开发
简单手写实现类组件的Ref
简单手写实现类组件的Ref
74 0
|
前端开发 JavaScript
简单手写实现元素的Ref
简单手写实现元素的Ref
75 0