Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Refs and the DOM揭秘 #2

Open
sisterAn opened this issue Feb 16, 2019 · 0 comments
Open

React Refs and the DOM揭秘 #2

sisterAn opened this issue Feb 16, 2019 · 0 comments

Comments

@sisterAn
Copy link
Owner

sisterAn commented Feb 16, 2019

什么是Ref

React的官方介绍是这样的:

In the typical React dataflow, props are the only way that parent components interact with their children. To modify a child, you re-render it with new props. However, there are a few cases where you need to imperatively modify a child outside of the typical dataflow. The child to be modified could be an instance of a React component, or it could be a DOM element. For both of these cases, React provides an escape hatch.

其中提到了这几个概念:

在典型的React数据流理念中,父组件跟子组件的交互都是通过传递属性(properties)实现的。如果父组件需要修改子组件,只需要将新的属性传递给子组件,由子组件来实现具体的绘制逻辑。

在特殊的情况下,如果你需要命令式(imperatively)的修改子组件,React也提供了应急的处理办法--Ref。

Ref 既支持修改DOM元素,也支持修改自定义的组件。

什么是声明式编程(Declarative Programming)

值得一提的是当中声明式编程(Declarative Programming)和命令式编程(Imperative Programming)的区别。声明式编程的特点是只描述要实现的结果,而不关心如何一步一步实现的,而命令式编程则相反,必须每个步骤都写清楚。我们可以根据语义直观的理解代码的功能是:针对数组的每一个元素,将它的值打印出来。不必关心实现其的细节。而命令式编程必须将每行代码读懂,然后再整合起来理解总体实现的功能。

React有2个基石设计理念:一个是声明式编程,一个是函数式编程。函数式编程以后有机会再展开讲。声明式编程的特点体现在2方面:

组件定义的时候,所有的实现逻辑都封装在组件的内部,通过state管理,对外只暴露属性。

组件使用的时候,组件调用者通过传入不同属性的值来达到展现不同内容的效果。一切效果都是事先定义好的,至于效果是怎么实现的,组件调用者不需要关心。

因此,在使用React的时候,一般很少需要用到Ref。那么,Ref的使用场景又是什么?

Ref使用场景

React官方文档是这么说的:

There are a few good use cases for refs: Managing focus, text selection, or media playback.Triggering imperative animations.Integrating with third-party DOM libraries. Avoid using refs for anything that can be done declaratively.

简单理解就是,控制一些DOM原生的效果,如输入框的聚焦效果和选中效果等;触发一些命令式的动画;集成第三方的DOM库。最后还补了一句:如果要实现的功能可以通过声明式的方式实现,就不要借助Ref。

通常我们会利用 render 方法得到一个 App 组件的实例,然后就可以对它做一些操作。但在组件内,JSX 是不会返回一个组件的实例的,它只是一个ReactElement,只是告诉你,React被挂载的组件应该涨什么样:

const myApp = <App />

refs就是由此而生,它是React组件中非常特殊的props, 可以附加到任何一个组件上,从字面意思上看,refs即reference,组件被调用时会创建一个该组件的实例,而refd就会指向这个实例。

Ref用法

如果作用在原生的DOM元素上,通过Ref获取的是DOM元素,可以直接操作DOM的API:

class CustomTextInput extends React.Component {  
    constructor(props) {    
        super(props);        
        this.focusTextInput = this.focusTextInput.bind(this);  
    } 
    focusTextInput() {    
        if(this.myTextInput !== null) {         
            this.textInput.current.focus();    
        }  
    }  
    render() {    
        return (      
            <div>        
                <input type="text" ref={(ref) => this.myTextInput = ref} />        
                <input type="button" value="Focus the text input" onClick={this.focusTextInput}/>      
            </div>    

        );  
    } 
}

如果作用在自定义组件,Ref获取的是组件的实例,可以直接操作组件内的任意方法:

class AutoFocusTextInput extends React.Component {  
    constructor(props) {    
        super(props);    
        this.textInput = React.createRef();  
    }  
    componentDidMount() {    
        this.textInput.current.focusTextInput();  
    }  
    render() {    
        return (      
            <CustomTextInput ref={this.textInput} />    
        );  
    } 
}

Ref总结

为了防止内存泄漏,当卸载一个组件时,组件里所有的refs就会变成null。

值得注意的是,findDOMNoderefs 都无法用于无状态组件中。因为,无状态组件挂载时只是方法调用,并没有创建实例。

对于 React 组件来讲,refs 会指向一个组件类实例,所以可以调用该类定义的任何方法。如果需要访问该组件的真实 DOM ,可以用 ReactDOM 。 findDOMNode来找到 DOM 节点,但并不推荐这样做,因为这大部分情况下都打破了封装性,而且通常都能用更清晰的方法在React中构建代码。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant