美文网首页
React ref属性使用

React ref属性使用

作者: Android_冯星 | 来源:发表于2018-08-23 17:43 被阅读0次

    React Refs

    React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。

    这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例。

    ref顾名思义我们知道,其实它就可以被看座是一个组件的参考,也可以说是一个标识。作为组件的属性,其属性值可以是一个字符串也可以是一个函数。

    其实,ref的使用不是必须的。即使是在其适用的场景中也不是非用不可的,因为使用ref实现的功能同样可以转化成其他的方法来实现。但是,既然ref有其适用的场景,那也就是说ref自有其优势。关于这一点和ref的适用场景,官方文档中是这样说的:

    在从 render 方法中返回 UI 结构之后,你可能想冲出 React 虚拟 DOM 的限制,在 render 返回的组件实例上调用某些方法。通常来说,这样做对于应用中的数据流动是不必要的,因为活跃的数据( Reactive data )流总是确保最新的 props 被传递到每一个从 render() 输出的子级中去。然而,仍然有几个场景使用这种方式是必须的,或者说是有益的:查找渲染出的组件的DOM标记(可以认为是DOM的标识ID),在一个大型的非React应用中使用React组件或者是将你现有的代码转化成React。

    string 使用方法

    绑定一个 ref 属性到 render 的返回值上:

    <input ref="myInput" />
    在其它代码中,通过 this.refs 获取支撑实例:

    var input = this.refs.myInput;
    var inputValue = input.value;
    var inputRect = input.getBoundingClientRect();
    

    ref作为回调函数的方式去使用

    class Input extends Component {
        constructor(props){
            super(props);
        }
        
        focus = () => {
            this.textInput.focus();
        }
        
        render(){
            return (
                <div>
                    <input ref={(input) => { this.textInput = input }} />
                </div>
            )
        }
    }
    
    
    input参数是哪来的

    当我们在DOM Element中使用ref时,回调函数将接收当前的DOM元素作为参数,然后存储一个指向这个DOM元素的引用。那么在示例代码中,我们已经把input元素存储在了this.textInput中,在focus函数中直接使用原生DOM API实现focus聚焦。

    回调函数什么时候被调用

    答案是当组件挂载后和卸载后,以及ref属性本身发生变化时,回调函数就会被调用。

    可以在组件实例中使用ref

    前面的示例代码是在DOM添加ref属性,那么我们来看看如何在组件实例中使用。再上代码:

    //<Input>来源于上面的示例代码👆
    class AutoFocusTextInput extends Component {
        componentDidMount(){
            this.textInput.focus();
        }
        
        render(){
            return (
                <Input ref={(input) => { this.textInput = input }}>
            )
        }
    }
    

    当我们在<Input>中添加ref属性时,其回调函数接收已经挂载的组件实例<Input>作为参数,并通过this.textInput访问到其内部的focus方法。也就是说,上面的示例代码实现了当AutoFocusTextInput组件挂载后<Input>组件的自动聚焦。
    接下来文档指出,<Input>组件必须是使用class声明的组件,不然无法使用。这意味着React逐渐与ES6全面接轨了。

    不能在无状态组件中使用ref

    原因很简单,因为ref引用的是组件的实例,而无状态组件准确的说是个函数组件(Functional Component),没有实例。上代码:

    function MyFunctionalComponent() {
        return <input />;
    }
    
    class Parent extends React.Component {
        render() {
            return (
                <MyFunctionalComponent
                    ref={(input) => { this.textInput = input; }} />
            );
        }
    }
    

    上面的代码是无法正常工作的。

    父组件的ref回调函数可以使用子组件的DOM。

    这是Facebook非常不推荐的做法,因为这样会打破组件的封装性,这种方法只是某些特殊场景下的权宜之计。我们看看如何实现,上代码:

    function CustomTextInput(props) {
        return (
            <div>
                <input ref={props.inputRef} />
            </div>
        );
    }
    
    class Parent extends React.Component {
        render() {
            return (
                <CustomTextInput
                    inputRef={el => this.inputElement = el}
                />
            );
        }
    }
    

    原理就是父组件把ref的回调函数当做inputRefprops传递给子组件,然后子组件<CustomTextInput>把这个函数和当前的DOM绑定,最终的结果是父组件<Parent>的this.inputElement存储的DOM是子组件<CustomTextInput>中的input。
    同样的道理,如果A组件是B组件的父组件,B组件是C组件的父组件,那么可用上面的方法,让A组件拿到C组件的DOM。但是官方态度是discouraged,这种多级调用确实不雅,我们确实需要考虑其他更好的方案了。

    作者:ssssyoki
    链接:https://juejin.im/post/5927f51244d904006414925a
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    相关文章

      网友评论

          本文标题:React ref属性使用

          本文链接:https://www.haomeiwen.com/subject/acrmiftx.html