• React中refs的理解


    React中refs的理解

    Refs提供了一种方式,允许我们访问DOM节点或在render方法中创建的React元素。

    描述

    在典型的React数据流中,props是父组件与子组件交互的唯一方式,要修改一个子组件,你需要使用新的props来重新渲染它,但是在某些情况下,你需要在典型数据流之外强制修改子组件,被修改的子组件可能是一个React组件的实例,也可能是一个DOM元素,对于这两种情况React都提供了解决办法。
    避免使用refs来做任何可以通过声明式实现来完成的事情,通常在可以使用propsstate的情况下勿依赖refs,下面是几个适合使用refs的情况:

    • 管理焦点、文本选择或媒体播放。
    • 触发强制动画。
    • 集成第三方DOM库。

    使用

    React提供的这个ref属性,表示为对组件真正实例的引用,其实就是ReactDOM.render()返回的组件实例,需要区分一下渲染组件与渲染原生DOM元素,渲染组件时返回的是组件实例,而渲染DOM元素时,返回是具体的DOM节点,Reactref3种用法。

    字符串

    ref可以直接设置为字符串值,这种方式基本不推荐使用,或者在未来的React版本中不会再支持该方式。这主要是因为使用字符串导致的一些问题,例如当ref定义为string时,需要React追踪当前正在渲染的组件,在reconciliation阶段,React Element创建和更新的过程中,ref会被封装为一个闭包函数,等待commit阶段被执行,这会对React的性能产生一些影响等。

    class InputOne extends React.Component {
        componentDidMount() {
            this.refs.inputRef.value = 1;
          }
        render() {
            return <input ref="inputRef" />;
        }
    }
    

    回调

    React支持给任意组件添加特殊属性,ref属性接受一个回调函数,其在组件被加载或卸载时会立即执行。

    • 当给HTML元素添加ref属性时,ref回调接收了底层的DOM元素作为参数。
    • 当给组件添加ref属性时,ref回调接收当前组件实例作为参数。
    • 当组件卸载的时候,会传入null
    • ref回调会在componentDidMountcomponentDidUpdate等生命周期回调之前执行。

    Callback Ref我们通常会使用内联函数的形式,那么每次渲染都会重新创建,由于React会清理旧的ref然后设置新的,因此更新期间会调用两次,第一次为null,如果在Callback中带有业务逻辑的话,可能会出错,可以通过将Callback定义成类成员函数并进行绑定的方式避免。

    class InputTwo extends React.Component {
        componentDidMount() {
            this.inputRef.value = 2;
          }
        render() {
            return <input ref={(element) =>this.inputRef = element} />;
        }
    }
    

    API创建

    React v16.3中经0017-new-create-ref提案引入了新的React.createRefAPI,当ref被传递给render中的元素时,对该节点的引用可以在refcurrent属性中被访问,ref的值根据节点的类型而有所不同:

    • ref属性用于HTML元素时,构造函数中使用React.createRef()创建的ref接收底层DOM元素作为其current属性。
    • ref属性用于自定义class组件时,ref对象接收组件的挂载实例作为其current属性。
    • 不能在函数组件上使用ref属性,因为他们没有实例。

    对比新的CreateRefCallback Ref,并没有压倒性的优势,只是希望成为一个便捷的特性,在性能上会会有微小的优势,Callback Ref采用了组件Render过程中在闭包函数中分配ref的模式,而CreateRef则采用了Object Ref

    class InputThree extends React.Component {
        constructor(props) {
            super(props);
            this.inputRef = React.createRef();
        }
        componentDidMount() {
            this.inputRef.current.value = 3;
        }
        render() {
            return <input ref={this.inputRef} />;
        }
    }
    

    示例

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="UTF-8" />
        <title>React</title>
    </head>
    
    <body>
        <div id="root"></div>
    </body>
    <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="text/babel">
        class InputOne extends React.Component {
            componentDidMount() {
                this.refs.inputRef.value = 1;
              }
            render() {
                return <input ref="inputRef" />;
            }
        }
    
        class InputTwo extends React.Component {
            componentDidMount() {
                this.inputRef.value = 2;
              }
            render() {
                return <input ref={(element) =>this.inputRef = element} />;
            }
        }
    
        class InputThree extends React.Component {
            constructor(props) {
                super(props);
                this.inputRef = React.createRef();
            }
            componentDidMount() {
                this.inputRef.current.value = 3;
            }
            render() {
                return <input ref={this.inputRef} />;
            }
        }
        
    
        var vm = ReactDOM.render(
            <>
                <InputOne />
                <InputTwo />
                <InputThree />
            </>,
            document.getElementById("root")
        );
    </script>
    
    </html>
    
    

    每日一题

    https://github.com/WindrunnerMax/EveryDay
    

    参考

    https://zhuanlan.zhihu.com/p/40462264
    https://www.jianshu.com/p/4e2357ea1ba1
    https://juejin.cn/post/6844903809274085389
    https://juejin.cn/post/6844904048882106375
    https://segmentfault.com/a/1190000008665915
    https://zh-hans.reactjs.org/docs/refs-and-the-dom.html
    
  • 相关阅读:
    SQL SERVER 2012 第三章 使用INSERT语句添加数据
    SQL SERVER 2012 第三章 T-SQL 基本语句 having子句
    T4 模板生产 多文件
    RAC+DG修改sys密码
    数据泵导入,报错:ORA-12899: value too large for column "SCOTT"."TEST112"."JOIN" (actual: 9, maximum: 8)
    grep过滤空行和注释行
    char与varchar2字符类型的区别
    Oracle不知道用户密码情况下,如何在不更改密码的前提下解锁用户或者延期密码有效期
    数据泵导出报错ORA-31693 ORA-02354 ORA-01466
    安装ogg软件报错:[INS-75012]Sofware Location specified is already an existing Oracle
  • 原文地址:https://www.cnblogs.com/WindrunnerMax/p/14295030.html
Copyright © 2020-2023  润新知