学习笔记:React组件实例的三大核心属性(Refs)

141 阅读2分钟

1.Refs是什么

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

2.如何使用Refs

1.字符串形式的ref(不推荐)

最方便的一种方式,但是不推荐,因为会有性能上的问题

class Demo extends React.Component {
    alertInput1 = () => {
        const { input1 } = this.refs;
        alert(input1.value);
    }
    alertInput2 = () => {
        const { input2 } = this.refs;
        alert(input2.value);
    }
    
    render() {
        return (
            <div>
                // 使用字符串形式的ref标记input元素,react会帮我们在渲染这个input元素时,将它存储在组件实例对象的refs属性中
                <input ref="input1" type="text" placeholder="点击按钮显示输入内容" />&nbsp;
                <button onClick={this.alertInput1} >点击显示左侧输入内容</button>
                <input onBlur={this.alertInput2} ref="input2" type="text" placeholder="失去焦点显示输入内容" />&nbsp;
            </div>
        )
    }
}

2.回调函数形式的ref

class Demo extends React.Component {
    alertInput1 = () => {
        const { input1 } = this;
        alert(input1.value);
    }
    alertInput2 = () => {
        const { input2 } = this;
        alert(input2.value);
    }
    
    render() {
        return (
            <div>
                // 使用回调函数的形式的ref,react会帮我们在渲染这个input元素时调用,调用时会传入一个参数,这个参数就是input元素
                <input ref="e => this.input1 = e" type="text" placeholder="点击按钮显示输入内容" />&nbsp;
                <button onClick={this.alertInput1} >点击显示左侧输入内容</button>
                <input onBlur={this.alertInput2} ref="e => this.input2 = e" type="text" placeholder="失去焦点显示输入内容" />&nbsp;
            </div>
        )
    }
}

React官网解释:如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。

class Demo extends React.Component {
    state = { status: true }
    updateStatus = () => {
        cosnt { status } = this.state;
        // 调用setState更改state内的值时,会触发重新渲染,即组件实例调用render方法
        this.setState({ status: !status });
    }
    alertInput = () => {
        const { input } = this;
        alert(input.value);
    }
    saveInput = (e) => {
        this.input = e;
        console.log('input ref: ', e); // 更新渲染时不会被触发
    }
    
    render() {
        return (
            <div>
                // 当触发更新渲染时 Output: input ref: null
                //                         input ref: input
                <input ref="(e) => { this.input = e; console.log('input ref: ', e) }" type="text" placeholder="点击按钮显示输入内容" />&nbsp;
                // 如果使用如下class 的绑定函数方式,则可以避免上述问题
                {/*<input ref="this.saveInput" type="text" placeholder="点击按钮显示输入内容" />*/}&nbsp;
                <button onClick={this.alertInput1} >点击显示左侧输入内容</button>
                <button onClick={this.updateStatus} >点击切换状态</button>
            </div>
        )
    }
}

3.使用React.creatRef的ref

class Demo extends React.Component {
    myRef1 = React.creatRef();
    myRef2 = React.creatRef();
    alertInput1 = () => {
        alert(this.myRef1.current.value);
    }
    alertInput2 = () => {
        alert(this.myRef2.current.value);
    }
    
    render() {
        return (
            <div>
                // 使用creatRef形式的ref,react会帮我们在渲染这个input元素时创建一个容器,该容器只会存储这一个元素,并且存储在该容器的current属性中
                <input ref={this.myRef1} type="text" placeholder="点击按钮显示输入内容" />&nbsp;
                <button onClick={this.alertInput1} >点击显示左侧输入内容</button>
                <input onBlur={this.alertInput2} ref={this.myRef2} type="text" placeholder="失去焦点显示输入内容" />&nbsp;
            </div>
        )
    }
}

注意:请勿过度使用Refs

class Demo extends React.Component {
    myRef1 = React.creatRef();
    alertInput1 = () => {
        alert(this.myRef1.current.value);
    }
    alertInput2 = (event) => {
        alert(event.target.value);
    }
    
    render() {
        return (
            <div>
                <input ref={this.myRef1} type="text" placeholder="点击按钮显示输入内容" />&nbsp;
                <button onClick={this.alertInput1} >点击显示左侧输入内容</button>
                // 当触发事件的元素和数据来源的元素是同一个时,可以使用原生的event.target获取元素
                <input onBlur={this.alertInput2} ref={this.myRef2} type="text" placeholder="失去焦点显示输入内容" />&nbsp;
            </div>
        )
    }
}