广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >React Refs 的使用forwardRef 源码示例解析
  • 459
分享到

React Refs 的使用forwardRef 源码示例解析

React Refs使用forwardRefReact Refs 2022-11-13 19:11:09 459人浏览 独家记忆
摘要

目录三种使用方式1. String Refs2. 回调 Refs3. createRef两种使用目的Refs 转发createRef 源码forwardRef 源码三种使用方式 Re

三种使用方式

React 提供了 Refs,帮助我们访问 DOM 节点或在 render 方法中创建的 React 元素。

React 提供了三种使用 Ref 的方式:

1. String Refs

class App extends React.Component {
    constructor(props) {
        super(props)
    }
    componentDidMount() {
        setTimeout(() => {
             // 2. 通过 this.refs.xxx 获取 DOM 节点
             this.refs.textInput.value = 'new value'
        }, 2000)
    }
    render() {
        // 1. ref 直接传入一个字符串
        return (
            <div>
              <input ref="textInput" value='value' />
            </div>
        )
    }
}
root.render(<App />);

2. 回调 Refs

class App extends React.Component {
    constructor(props) {
        super(props)
    }
    componentDidMount() {
        setTimeout(() => {
              // 2. 通过实例属性获取 DOM 节点
              this.textInput.value = 'new value'
        }, 2000)
    }
    render() {
        // 1. ref 传入一个回调函数
        // 该函数中接受 React 组件实例或 DOM 元素作为参数
        // 我们通常会将其存储到具体的实例属性(this.textInput)
        return (
            <div>
              <input ref={(element) => {
                this.textInput = element;
              }} value='value' />
            </div>
        )
    }
}
root.render(<App />);

3. createRef

class App extends React.Component {
    constructor(props) {
        super(props)
        // 1. 使用 createRef 创建 Refs
        // 并将 Refs 分配给实例属性 textInputRef,以便在整个组件中引用
        this.textInputRef = React.createRef();
    }
    componentDidMount() {
        setTimeout(() => {
            // 3. 通过 Refs 的 current 属性进行引用
            this.textInputRef.current.value = 'new value'
        }, 2000)
    }
    render() {
        // 2. 通过 ref 属性附加到 React 元素
        return (
            <div>
              <input ref={this.textInputRef} value='value' />
            </div>
        )
    }
}

这是最被推荐使用的方式。

两种使用目的

Refs 除了用于获取具体的 DOM 节点外,也可以获取 Class 组件的实例,当获取到实例后,可以调用其中的方法,从而强制执行,比如动画之类的效果。

我们举一个获取组件实例的例子:

class Input extends React.Component {
    constructor(props) {
        super(props)
        this.textInputRef = React.createRef();
    }
    handleFocus() {
        this.textInputRef.current.focus();
    }
    render() {
        return <input ref={this.textInputRef} value='value' />
    }
}
class App extends React.Component {
    constructor(props) {
        super(props)
        this.inputRef = React.createRef();
    }
    componentDidMount() {
        setTimeout(() => {
                this.inputRef.current.handleFocus()
        }, 2000)
    }
    render() {
        return (
            <div>
              <Input ref={this.inputRef} value='value' />
            </div>
        )
    }
}

在这个例子中,我们通过 this.inputRef.current 获取到 Input 组件的实例,并调用了实例的 handleFocus 方法,在这个方法中,又通过 Refs 获取到具体的 DOM 元素,执行了 focus 原生方法。

Refs 转发

有的时候,我们开发一个组件,这个组件需要对组件使用者提供一个 ref 属性,用于让组件使用者获取具体的 DOM 元素,我们就需要进行 Refs 转发,这对于 class 组件并不是一个问题,举个示例代码:

class Child extends React.Component {
    render() {
        const {inputRef, ...rest} = this.props;
        // 3. 这里将 props 中的 inputRef 赋给 DOM 元素的 ref
        return <input ref={inputRef} {...rest} placeholder="value" />
    }
}
class Parent extends React.Component {
    constructor(props) {
        super(props)
        // 1. 创建 refs
        this.inputRef = React.createRef();
    }
    componentDidMount() {
        setTimeout(() => {
            // 4. 使用 this.inputRef.current 获取子组件中渲染的 DOM 节点
            this.inputRef.current.value = 'new value'
        }, 2000)
    }
    render() {
        // 2. 因为 ref 属性不能通过 this.props 获取,所以这里换了一个属性名
        return <Child inputRef={this.inputRef} />
    }
}

但对于函数式组件,这却是一个问题。

我们是不能在函数组件上使用 ref 属性的,因为函数组件没有实例。

所以 React 提供了 forwardRef 这个 api,我们直接看使用示例:

// 3. 子组件通过 forwardRef 获取 ref,并通过 ref 属性绑定 React 元素
const Child = forwardRef((props, ref) => (
  <input ref={ref} placeholder="value" />
));
class Parent extends React.Component {
    constructor(props) {
        super(props)
        // 1. 创建 refs
        this.inputRef = React.createRef();
    }
    componentDidMount() {
        setTimeout(() => {
            // 4. 使用 this.inputRef.current 获取子组件中渲染的 DOM 节点
            this.inputRef.current.value = 'new value'
        }, 2000)
    }
    render() {
        // 2. 传给子组件的 ref 属性
        return <Child ref={this.inputRef} />
    }
}

尤其是在我们编写高阶组件的时候,往往要实现 refs 转发。我们知道,一个高阶组件,会接受一个组件,返回一个包裹后的新组件,从而实现某种功能的增强。

但也正是如此,我们添加 ref,获取的会是包裹后的新组件的实例,而非被包裹的组件实例,这就可能会导致一些问题。

createRef 源码

现在我们看下 createRef 的源码,源码的位置在 /packages/react/src/ReactCreateRef.js,代码其实很简单,就只是返回了一个具有 current 属性的对象:

// 简化后
export function createRef() {
  const refObject = {
    current: null,
  };
  return refObject;
}

在渲染的过程中,refObject.current 会被赋予具体的值。

forwardRef 源码

那 forwardRef 源码呢?源码的位置在 /packages/react/src/ReactForwardRef.js,代码也很简单:

// 简化后
const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
export function forwardRef(render) {
  const elementType = {
    $$typeof: REACT_FORWARD_REF_TYPE,
    render,
  };
  return elementType;
}

但是要注意这里的 $$typeof,尽管这里是 REACT_FORWARD_REF_TYPE,但最终创建的 React 元素的 $$typeof 依然为 REACT_ELEMENT_TYPE

关于 createElement源码分析参考 《React 之 createElement 源码解读》,我们这里简单分析一下,以 InputComponent 为例:

// 使用 forwardRef
const InputComponent = forwardRef(({value}, ref) => (
  <input ref={ref} className="FancyButton" value={value} />
));
// 根据 forwardRef 的源码,最终返回的对象格式为:
const InputComponent = {
    $$typeof: REACT_FORWARD_REF_TYPE,
    render,
}
// 使用组件
const result = <InputComponent />
// Bable 将其转译为:
const result = React.createElement(InputComponent, null);
// 最终返回的对象为:
const result = {
  $$typeof: REACT_ELEMENT_TYPE,
  type: {
    $$typeof: REACT_FORWARD_REF_TYPE,
    render,
  }
}

我们尝试着打印一下最终返回的对象,确实也是这样的结构:

React 系列

React 之 createElement 源码解读

React 之元素与组件的区别

以上就是React 之 Refs 的使用和 forwardRef 的源码解读的详细内容,更多关于React Refs使用forwardRef 的资料请关注编程网其它相关文章!

--结束END--

本文标题: React Refs 的使用forwardRef 源码示例解析

本文链接: https://www.lsjlt.com/news/170868.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • React Refs 的使用forwardRef 源码示例解析
    目录三种使用方式1. String Refs2. 回调 Refs3. createRef两种使用目的Refs 转发createRef 源码forwardRef 源码三种使用方式 Re...
    99+
    2022-11-13
    React Refs使用forwardRef React Refs
  • React中setState源码的示例分析
    这篇文章将为大家详细讲解有关React中setState源码的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。React作为一门前端框架,虽然只是focus在MVV...
    99+
    2022-10-19
  • Go Excelize API源码解析GetSheetFormatPr使用示例
    目录一、Go-Excelize简介二、GetSheetFormatPr一、Go-Excelize简介 Excelize 是 Go 语言编写的用于操作 Office Excel 文档基...
    99+
    2022-11-11
  • react-native源码图片缓存问题的示例分析
    小编给大家分享一下react-native源码图片缓存问题的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!为xcode模...
    99+
    2022-10-19
  • Java源码解析之ConcurrentHashMap的示例分析
    小编给大家分享一下Java源码解析之ConcurrentHashMap的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!早期 ConcurrentHashMap,其实现是基于:分离锁,也就是将内部进行分段(Segme...
    99+
    2023-06-15
  • Vue中AST源码解析的示例分析
    这篇文章主要介绍Vue中AST源码解析的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!从这个函数开始的:// Line-3924  Vue.prototy...
    99+
    2022-10-19
  • 从Context源码实现谈React性能优化的示例分析
    这篇文章给大家分享的是有关从Context源码实现谈React性能优化的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。组件render的时机Context的实现与组件的r...
    99+
    2022-10-19
  • Java源码解析之接口Collection的示例分析
    小编给大家分享一下Java源码解析之接口Collection的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、图示二、方法定义我们先想一想,公司如果要我...
    99+
    2023-06-15
  • c++可变参数模板使用示例源码解析
    目录前言认识可变模板参数使用可变模板参数递归法特例化包拓展完美转发总结前言 我们知道,C++模板能力很强大,比起Java泛型这种语法糖来说,简直就是降维打击。而其中,可变参数模板,...
    99+
    2023-01-13
    c++可变参数模板 c++可变参数
  • React 错误边界Error Boundary使用示例解析
    目录我们为什么需要错误边界如何使用错误边界组件使用错误边界需要注意什么我们为什么需要错误边界 在React组件中可能会由于某些JavaScript错误,导致一些无法追踪的错误,导致应...
    99+
    2022-11-13
  • Android StateMachine使用举例及源码解析
    Android frameworks源码StateMachine使用举例及源码解析 工作中有一同事说到Android状态机StateMachin...
    99+
    2022-06-06
    源码 Android
  • Spring源码解析之编程式事务的示例分析
    这篇文章主要为大家展示了“Spring源码解析之编程式事务的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Spring源码解析之编程式事务的示例分析”这篇文章吧。一、前言在Spring中...
    99+
    2023-06-15
  • Android 资源加载使用伪代码示例分析
    目录引言Resource是什么?基础概念getTextgetDrawable小结TipsgetColor总结引言 聊到 Android 的 资源加载 ,每一个开发同学都会非常熟悉,毕...
    99+
    2022-11-13
    Android 资源加载 Android 加载
  • Vue源码解析之数据响应系统的示例分析
    这篇文章主要介绍Vue源码解析之数据响应系统的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!数据双向绑定的思路1. 对象先来看元素是对象的情况。假设我们有一个对象和一个监测方...
    99+
    2022-10-19
  • Spring源码解析之推断构造方法的示例分析
    小编给大家分享一下Spring源码解析之推断构造方法的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Spring推断构造方法贴个测试代码直接开干,这只是个...
    99+
    2023-06-15
  • react源码中的生命周期和事件系统实例解析
    目录引言jsx的编译结果React组件的生命周期组件挂载的时候的执行顺序组件更新的时候的执行顺序组件卸载的时候执行顺序组件在发生错误的时候执行顺序listenToAllSupport...
    99+
    2023-01-03
    react源码生命周期事件系统 react生命周期
  • Python 装饰器常用的创建方式及源码示例解析
    目录装饰器简介基础通用装饰器源码示例执行结果带参数装饰器源码示例源码结果源码解析多装饰器执行顺序源码示例执行结果解析类装饰器源码示例执行结果解析装饰器简介 装饰器(decorator...
    99+
    2022-11-10
  • react 源码中位运算符的使用详解
    位运算符基本使用 按位与(&):a & b对于每一个比特位,两个操作数都为 1 时, 结果为 1, 否则为 0按位或(|):a | b对于每一个比特位,两个操作数都为...
    99+
    2022-11-13
  • React中的ref属性的使用示例详解
    目录ref 简介1. 字符串形式的ref2. create形式的ref3. 回调函数形式的ref总结:ref 简介 React提供的这个ref属性,表示为对组件真正实例的引用,其实就...
    99+
    2023-05-17
    React ref属性使用 React ref属性
  • ResponseBodyAdvice的使用原理源码解析
    目录前言正文一. ResponseBodyAdvice的使用二. ResponseBodyAdvice的原理三. ResponseBodyAdvice的加载总结前言 Respons...
    99+
    2023-03-13
    ResponseBodyAdvice原理 ResponseBodyAdvice源码解析
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作