• React - ref 命令为什么代替父子组件的数据传递


    前言

    我们在谈论受控组件的时候,会去使用父子通信的方式去进行数据传递,从而达到组件的受控,其实并非这一种方案,当我们对表单组件进行受控处理的时候,往往会使用 ref 命令去进行数据传递,使用传统的父子通信当然可以实现,只不过对于表单组件来说,ref 更加的便捷


    使用父子通信解决表单域的数据传输问题

    既然说是表单域组件,那么我们就写一个表单域组件出来

    import React, { Component } from 'react';
    import Field from './Field';
    
    export default class App extends Component {
      render() {
        return (
          <section>
            <h1>登录页面</h1>
    
            <Field label="用户名" type="text"></Field>
    
            <Field label="密码" type="password"></Field>
    
            <button>Login</button>
            <button>clear</button>
          </section>
        );
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    import React, { Component } from 'react';
    
    export default class App extends Component {
      render() {
        return (
          <section style={{ backgroundColor: 'green' }}>
            <label htmlFor="">{this.props.label}</label>
            <input type={this.props.type} />
          </section>
        );
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    表单域组件

    接下来我们想点击登录,获取到用户名以及密码,点击清除会把表单中的数据清空

    如果我们使用父子通信的方法来实现的话

    • 父组件:
    import React, { Component } from 'react';
    import Field from './Field';
    
    export default class App extends Component {
      constructor() {
        super();
        this.state = {
          username: '',
          password: '',
        };
      }
    
      render() {
        return (
          <section>
            <h1>登录页面</h1>
    
            <Field
              label="用户名"
              type="text"
              value={this.state.username}
              iptValue={value => {
                this.setState({
                  username: value,
                });
              }}
            ></Field>
    
            <Field
              label="密码"
              type="password"
              value={this.state.password}
              iptValue={value => {
                this.setState({
                  password: value,
                });
              }}
            ></Field>
    
            <button
              onClick={() => {
                console.log({
                  username: this.state.username,
                  password: this.state.password,
                });
              }}
            >
              Login
            </button>
            <button
              onClick={() => {
                this.setState({
                  username: '',
                  password: '',
                });
              }}
            >
              clear
            </button>
          </section>
        );
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 子组件:
    import React, { Component } from 'react';
    
    export default class App extends Component {
      render() {
        return (
          <section style={{ backgroundColor: 'green' }}>
            <label htmlFor="">{this.props.label}</label>
            <input
              type={this.props.type}
              value={this.props.value}
              onChange={e => {
                this.props.iptValue(e.target.value);
              }}
            />
          </section>
        );
      }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    获取用户信息

    OK,我们实现了,但是明显看来是比较繁琐的,一直在传来传去的 🤨


    ref是否更方便

    使用 ref 之后,我们不需要再进行频繁的父子传递了,子组件也可以有自己的私有状态并且不会影响信息的正常需求,这是为什么呢?因为我们使用了 ref 命令的话,ref是可以进行状态的传输的 😀


    获取用户信息

    子组件有自己的状态,自己修改自己

    • 子组件:
    import React, { Component } from 'react';
    
    export default class App extends Component {
      constructor() {
        super();
        this.state = {
          value: '',
        };
      }
    
      render() {
        return (
          <section style={{ backgroundColor: 'green' }}>
            <label htmlFor="">{this.props.label}</label>
            <input
              type={this.props.type}
              onChange={e => {
                this.setState({
                  value: e.target.value,
                });
              }}
            />
          </section>
        );
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    父组件通过 ref 可以直接拿到当前表单的虚拟DOM对象,里面的 state 属性中就有我们所需要的 value 值,非常的方便 😆

    • 父组件:
    import React, { Component } from 'react';
    import Field from './Field';
    
    export default class App extends Component {
      username = React.createRef();
      password = React.createRef();
    
      render() {
        return (
          <section>
            <h1>登录页面</h1>
    
            <Field label="用户名" type="text" ref={this.username}></Field>
    
            <Field label="密码" type="password" ref={this.password}></Field>
    
            <button
              onClick={() => {
                console.log({
                  username: this.username.current.state.value,
                  password: this.password.current.state.value,
                });
              }}
            >
              Login
            </button>
            <button>clear</button>
          </section>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    然后就是我们的清除需求了,该怎么实现?我们不能直接修改对象中的 value 值,那么还是需要使用受控理念来解决这个问题:


    清除表单数据

    • 子组件:
    import React, { Component } from 'react';
    
    export default class App extends Component {
      constructor() {
        super();
        this.state = {
          value: '',
        };
      }
    
      render() {
        return (
          <section style={{ backgroundColor: 'green' }}>
            <label htmlFor="">{this.props.label}</label>
            <input
              type={this.props.type}
              value={this.state.value}
              onChange={e => {
                this.setState({
                  value: e.target.value,
                });
              }}
            />
          </section>
        );
      }
    
      clear() {
        this.setState({
          value: '',
        });
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    我们给子组件中定义了一个方法,给到了一个 value 值,只要父组件触发了这个方法,那么对应的 状态以及 UI 中的 value 值都将变为 空,那么父组件怎么来触发呢?还记得我们通过 ref.current 拿到了什么吗?没错,我想说的是:通过 ref 拿到的子组件,其中的方法父组件也可以使用

    • 父组件修改部分:
    <button
      onClick={() => {
        this.username.current.clear();
        this.password.current.clear();
      }}
    >
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    蚂蚁金服杨军:蚂蚁数据分析平台的演进及数据分析方法的应用
    Java基础知识面试题(2022年最新版,持续更新...)整理
    AliLinux的使用Docker初始化服务(详细)
    Ubuntu18.04安装ROS、Gazebo、Mavros、PX4、QGC教程
    centos+jenkins+pycharm
    你知道.NET的字符串在内存中是如何存储的吗?
    游戏企业通关秘籍:华为云游戏全场景能力,开发+部署+运营“关关难过关关过”...
    真是学到了!——《Nginx的几个常用配置和技巧》
    某光伏行业头部企业联合谢宁老师《向华为学习 业务领先的战略规划SP(BLM)和战略解码BP(BEM)》训战内训成功举办
    nginx使用详解--反向代理
  • 原文地址:https://blog.csdn.net/weixin_63836026/article/details/126390299