简单手写实现函数组件的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打开自己文件的路径

正常运行,✌️~~~

目录
相关文章
|
3月前
|
前端开发 JavaScript API
第八章 react组件实例中三大属性之ref
第八章 react组件实例中三大属性之ref
|
21天前
|
JavaScript
Vue 创建自定义 ref 函数
Vue 创建自定义 ref 函数
|
21天前
|
JavaScript 前端开发 API
vue中的ref/reactive区别及原理
vue中的ref/reactive区别及原理
18 0
|
4月前
|
JavaScript 前端开发 开发者
|
4月前
【Vue2.0】—ref属性(十四)
【Vue2.0】—ref属性(十四)
|
前端开发
前端学习案例-ref的基本用法
前端学习案例-ref的基本用法
63 0
前端学习案例-ref的基本用法
|
前端开发
简单手写实现类组件的Ref
简单手写实现类组件的Ref
73 0
|
前端开发 JavaScript
简单手写实现元素的Ref
简单手写实现元素的Ref
73 0
|
缓存 JavaScript 测试技术
手写vue3源码——ref, computed 等
既然都需要使用 .value,是不是意味着,传入的数据都会被一个对象所包裹,基于这个特点,咋们是否可以使用class 里面有get, set 方法呢?class 本身是一个实例对象,刚好里面的get,set 可以对属性进行拦截存取行为
手写vue3源码——ref, computed 等
|
JavaScript 前端开发
react中ref使用方法解析
组件不是真实的DOM节点,在react开发中,官方也不建议直接去操作原生的DOM。组件的DOM节点是存在于内存中的一种数据结构,叫做虚拟DOM。如果需要从组件中获取真实的DOM节点,那就需要官方提供ref的属性。==React提供了ref用于访问在render方法中创建的DOM元素或者是React的组件实例
162 0
react中ref使用方法解析