资讯专栏INFORMATION COLUMN

React源码解析之React.createRef()/forwardRef()

aisuhua / 3690人阅读

摘要:一作用获取目标的实例使用源码可修改的不可变的对象没见过这种写法初始化对象,属性初始值为解析源码比较简单,就是返回了带有属性的二作用从父组件中获取子组件是的实例使用是没有实例的,因为它是,所以没有,所以不能通过来拿到实例将的传给子组件,并绑定

一、React.createRef()
GitHub:
https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/react/src/ReactCreateRef.js

作用:
获取目标elementDOM实例

使用:

import React from "react"

export default class Father extends  React.Completed{
  constructor(props){
    super(props)
    this.father=React.createRef()
  }

  componentDidMount(){
    this.father.current.value="hahhaha"
  }

  render(){
    return 
this is div
} }

源码:

import type {RefObject} from "shared/ReactTypes";

// an immutable object with a single mutable value
//可修改value的 不可变的对象
//没见过这种写法 :RefObject
export function createRef(): RefObject {
  //初始化ref对象,属性current初始值为null
  const refObject = {
    current: null,
  };
  if (__DEV__) {
    Object.seal(refObject);
  }
  return refObject;
}

解析:
源码比较简单,就是返回了带有current属性的refObject

二、React.forwardRef()
GitHub:
https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/react/src/forwardRef.js

作用:
从父组件中获取子组件是FunctionComponentDOM实例

使用:

import React from "react"
//funciton component是没有dom实例的,因为它是PureComponent,所以没有this,
// 所以不能通过createRef()来拿到实例

//将Father的father传给子组件,并绑定子组件的DOM实例,从而能在父组件拿到子组件的DOM实例
const Child=React.forwardRef((props,ref)=>{
  return 
child div
}) export default class Father extends React.Completed{ constructor(props){ super(props) this.father=React.createRef() } componentDidMount(){ this.father.current.value="hahhaha" } render(){ return } }

源码:

import {REACT_FORWARD_REF_TYPE, REACT_MEMO_TYPE} from "shared/ReactSymbols";

import warningWithoutStack from "shared/warningWithoutStack";

export default function forwardRef(
  render: (props: Props, ref: React$Ref) => React$Node,
) {
  //__DEV__可不看
  if (__DEV__) {
    if (render != null && render.$$typeof === REACT_MEMO_TYPE) {
      warningWithoutStack(
        false,
        "forwardRef requires a render function but received a `memo` " +
          "component. Instead of forwardRef(memo(...)), use " +
          "memo(forwardRef(...)).",
      );
    } else if (typeof render !== "function") {
      warningWithoutStack(
        false,
        "forwardRef requires a render function but was given %s.",
        render === null ? "null" : typeof render,
      );
    } else {
      warningWithoutStack(
        // Do not warn for 0 arguments because it could be due to usage of the "arguments" object
        render.length === 0 || render.length === 2,
        "forwardRef render functions accept exactly two parameters: props and ref. %s",
        render.length === 1
          ? "Did you forget to use the ref parameter?"
          : "Any additional parameter will be undefined.",
      );
    }

    if (render != null) {
      warningWithoutStack(
        render.defaultProps == null && render.propTypes == null,
        "forwardRef render functions do not support propTypes or defaultProps. " +
          "Did you accidentally pass a React component?",
      );
    }
  }

  return {
    //被forwardRef包裹后,组件内部的$$typeof是REACT_FORWARD_REF_TYPE
    $$typeof: REACT_FORWARD_REF_TYPE,
    //render即包装的FunctionComponent,ClassComponent是不用forwardRef的
    render,
  };
}

解析:
(1)不看__DEV__的话,返回的也是一个Object,也就是说,ChildforwardRef包裹后,React.forwardRef(Child)$$typeofREACT_FORWARD_REF_TYPE

注意:
一旦在Father组件中,用JSX引用了Child组件,那么就是React.createElement(React.forwardRef(Child)),又包裹了一层,此时的$$typeof`是`REACT_ELEMENT_TYPE`,`type`是`React.forwardRef(Child)`,`type`里面的`$$typeofREACT_FORWARD_REF_TYPE

const ReactElement = function(type,...) {
  const element = {
    $$typeof: REACT_ELEMENT_TYPE,
    type: type,
  };
}

(2)关于forward在高阶组件的用法,请参考:https://reactjs.org/docs/react-api.html#reactforwardref

(3)如何在antdPro/FunctionComponent中使用:
子:

const Child = (props,ref) => {
  const inputRef = React.useRef();
  React.useImperativeHandle(ref, () => ({
    focus: () => {
      // inputRef.current.focus();
      inputRef.current.value="aaaa"
    }
  }));

  return ()
}

export default React.forwardRef(Child)

父:

import Child from "./Child";
const Father=(props)=> {
   const rref= React.useRef(null)
   useEffect(() => {
    //console.log(rref.current,"rref33")
    rref.current.focus()
  }, []);
return ()
}

注意:
antdPro中使用的话,我试了是不好用dvaconnect包裹的,issue上作者也没回答,就关闭了:https://github.com/ant-design/ant-design-pro/issues/3123

useImperativeMethods已经重命名为useImperativeHandle,传送门:https://github.com/facebook/react/pull/14565

(完)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106050.html

相关文章

  • 基于React版本16.4的源码解析(一)

    摘要:本次分析的源码采用的是的版本核心接口提供了处理的工具集我们先来看看做了什么事情即当为空时,返回不为时调用,最终返回一个数组这里说一下,可以通过传入的对所有子组件进行操作,具体使用方法看下图参数通过配合的例子把父组件的赋值给每个子组件我们先不 本次分析的源码采用的是16.4.1的版本 核心接口 showImg(https://segmentfault.com/img/bVbeT9f?w=...

    joywek 评论0 收藏0
  • React 源码漂流(一) 起航

    摘要:在前端开发过程中,源码解读是必不可少的一个环节,我们直接进入主题,注意当前版本号。注意包文件仅仅是的必要的功能性的定义,它必须要结合一起使用下是,原生环境下是。 在前端开发过程中,源码解读是必不可少的一个环节,我们直接进入主题,注意当前 React 版本号 16.8.6。 注意:react 包文件仅仅是 React components 的必要的、功能性的定义,它必须要结合 React...

    Mr_zhang 评论0 收藏0
  • 如何在 React 组件中正确使用 Refs的指南

    摘要:通常在组件的构造函数内创建,使其在整个组件中可用。例如纯文本查看复制代码如上所示一个实例在构造函数中创建,并赋值给在方法内部,将构造函数中创建的传递给接下来,让我们看一个在组件中使用的示例。回调回调是在中使用的另一种方式。 使用 React 时,我们的默认思维方式应该是 不会强制修改 DOM ,而是通过传入 props 重新渲染组件。但是,有些情况却无法避免修改 DOM 。React ...

    Backache 评论0 收藏0
  • 精读《React16 新特性》

    摘要:引言于发布版本,时至今日已更新到,且引入了大量的令人振奋的新特性,本文章将带领大家根据更新的时间脉络了解的新特性。其作用是根据传递的来更新。新增等指针事件。 1 引言 于 2017.09.26 Facebook 发布 React v16.0 版本,时至今日已更新到 React v16.6,且引入了大量的令人振奋的新特性,本文章将带领大家根据 React 更新的时间脉络了解 React1...

    Nosee 评论0 收藏0
  • React v16.3.0: New lifecycles and context API

    摘要:为管理提供了一个新的方案,它为字符串提供了方便,并且没有任何缺点司徒正美注意除了新的外,回调将继续得到支持。例如司徒正美通常会将传递给它们包装的组件。 几天前,我们写了一篇关于即将到来的对我们的传统生命周期方法的变更的文章,包括逐步迁移策略。在React 16.3.0中,我们添加了一些新的生命周期方法来帮助迁移。我们还引入了新的API,用于长时间请求的特性:一个官方的上下文API、一个...

    zombieda 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<