每天学点React - 组件实例的三大核心属性之一 - refs与事件处理

90 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情

refs与事件处理

理解

组件内的标签可以定义ref属性来标识自己

使用方式

1. 字符串形式的ref(已过时

string类型的refs是最基础的一种方式,不过官网已经不推荐使用该方式来实现,因为string类型的refs存在一些问题,它可能会在未来的版本中被移除。

基础实现方式:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
        <!-- 测试容器 -->
        <div id="test"></div>

        <!-- 加载 React 核心库 -->
        <script type="text/javascript" src="../js/react.development.js"></script>
        <!-- 加载 React DOM 用于支持 React 操作 DOM -->
        <script type="text/javascript" src="../js/react-dom.development.js"></script>
        <!-- 加载 babel 用于将 jsx 转为 js -->
        <script type="text/javascript" src="../js/babel.min.js"></script>
    
        <!-- 设置类型为babel -->
        <script type="text/babel">
            // 创建组件
            class RefDemo extends React.Component{
                render(){
                    return (
                        <div>
                            <input ref='input1' type='text' placeholder='点击按钮弹窗'/>&nbsp;
                            <button onClick={this.showData1}>按钮</button>&nbsp;
                            <input onBlur={this.showData2} ref='input2' type='text' placeholder='失去焦点弹窗'/>
                        </div>
                    )
                }

                // 左侧数据展示
                showData1 = () => {
                    const {input1} = this.refs
                    alert(input1.value)
                }
                // 右侧数据展示
                showData2 = () => {
                    const {input2} = this.refs
                    alert(input2.value)
                }
            }
            

            // 将组件渲染到页面
            ReactDOM.render(<RefDemo/>, document.getElementById('test'))
        </script>
</body>
</html>

2. 回调形式的ref

在实例的属性中存储对 DOM 节点的引用。需要注意的是,如果ref是以回调函数形式定义的,在更新的过程中它会被执行两次,第一次传入参数为null,然后第二次才会传入参数DOM。因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。

回调形式的实现:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
        <!-- 测试容器 -->
        <div id="test"></div>

        <!-- 加载 React 核心库 -->
        <script type="text/javascript" src="../js/react.development.js"></script>
        <!-- 加载 React DOM 用于支持 React 操作 DOM -->
        <script type="text/javascript" src="../js/react-dom.development.js"></script>
        <!-- 加载 babel 用于将 jsx 转为 js -->
        <script type="text/javascript" src="../js/babel.min.js"></script>
    
        <!-- 设置类型为babel -->
        <script type="text/babel">
            // 创建组件
            class RefDemo extends React.Component{
                render(){
                    return (
                        <div>
                            <input ref={r => this.input1 = r} type='text' placeholder='点击按钮弹窗'/>&nbsp;
                            <button onClick={this.showData1}>按钮</button>&nbsp;
                            <input ref={r => this.input2 = r} onBlur={this.showData2} type='text' placeholder='失去焦点弹窗'/>
                        </div>
                    )
                }

                showData1 = () => {
                    const {input1} = this
                    alert(input1.value)
                }
                showData2 = () => {
                    const {input2} = this
                    alert(input2.value)
                }
            }
            

            // 将组件渲染到页面
            ReactDOM.render(<RefDemo/>, document.getElementById('test'))
        </script>
</body>
</html>

切换天气时,ref会被清除的效果如下: image.png

3. createRef创建ref容器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
        <!-- 测试容器 -->
        <div id="test"></div>

        <!-- 加载 React 核心库 -->
        <script type="text/javascript" src="../js/react.development.js"></script>
        <!-- 加载 React DOM 用于支持 React 操作 DOM -->
        <script type="text/javascript" src="../js/react-dom.development.js"></script>
        <!-- 加载 babel 用于将 jsx 转为 js -->
        <script type="text/javascript" src="../js/babel.min.js"></script>
    
        <!-- 设置类型为babel -->
        <script type="text/babel">
            // 创建组件
            class RefDemo extends React.Component{
                // 每个标签需定义自己的 ref 容器
                myRef1 = React.createRef()
                myRef2 = React.createRef()
                render(){
                    return (
                        <div>
                            <input ref={this.myRef1} type='text' placeholder='点击按钮弹窗'/>&nbsp;
                            <button onClick={this.showData1}>按钮</button>&nbsp;
                            <input onBlur={this.showData2} ref={this.myRef2} type='text' placeholder='失去焦点弹窗'/>
                        </div>
                    )
                }

                // 左侧数据展示
                showData1 = () => {
                    console.log(this.myRef1)
                    alert(this.myRef1.current.value)
                }
                // 右侧数据展示
                showData2 = () => {
                    alert(this.myRef2.current.value)
                }
            }
            

            // 将组件渲染到页面
            ReactDOM.render(<RefDemo/>, document.getElementById('test'))
        </script>
</body>
</html>

小结

  1. 字符串形式ref:能自动收集,简单快捷,但是有一些问题,未来版本可能会移除,能避免使用尽量避免;
  2. 回调形式ref:内联函数会有多次调用的问题,官网给出建议可以采用class形式来避免该问题,但多次调用问题在大多数情况下是无关紧要但,两种方式均可正常使用;
  3. createRef形式:较为麻烦,每个标签需要定义自己的一个ref容器,但是该方式为官网最推荐使用的一种方式。