React 学习笔记:组件通信

组件通信

组件为什么需要通信呢?这是因为组件是独立且封闭的单元,默认情况下,组件只能使用自己的数据,但是多个组件之间不可避免的要共享某些数据,为了实现这些功能,就需要打破组件的独立封闭性,让其与外界沟通。

父传子

在这里插入图片描述

React 中的数据只能从“辈分高”的组件传到“辈分低”的组件,所以 React 中数据只能是单向数据流,是自顶而下的。

  • 父组件将数据传给子组件通过 Props 实现,使用子组件的时候通过属性绑定数据,在组件内部通过 props 获取即可。
  • 父组件传递数据给子组件,父组件更新数据子组件自动接收更新后的数据,子组件是不能修改数据的

props

可以传递的数据类型
  • 字符串
  • 数字
  • 布尔
  • 数组
  • 对象
  • 函数
  • JSX (插槽)
类型检查

由于 props 都是别的组件传递的,在使用的时候如果数据类型不对,很容易造成组件内部逻辑出错,为了避免这种情况可以通过 prop-types 插件在创建组件的时候进行类型检查。

  • 安装 yarn add prop-types

常见的校验规则

  • 常见类型:array、bool、func、number、object、string
  • React元素类型:element
  • 必填项:isRequired
  • 特定结构的对象:shape({})

函数组件

import propTypes from 'prop-types'
function Father() {
  return (
    <Son name='孤城浪人'></Son>
  );
}
function Son(props) {
  return <div>{props.name}</div>
}
Son.propTypes = {
  name: propTypes.number
}
  • 类组件
function Father() {
  return (
    <Son name="孤城浪人"></Son>
  );
}

class Son extends React.Component {
  static propTypes = {
    name: propTypes.string
  }
  render() {
    return <div>{this.props.name}</div>
  }
}
默认值

给组件的 props 设置默认值,在未传入props的时候生效。有两种方式

  • 函数组件
function Father() {
  return (
    <Son></Son>
  );
}

function Son(props) {
  return <div>{props.name}</div>
}
Son.defaultProps = {
  // props属性:校验规则
  name: '孤城浪人'
}

新版react推荐使用参数默认值来实现

// 分页组件
function Father() {
  return (
    <Son></Son>
  );
}
function Son({ name = '孤城浪人' }) {
  return <div>{name}</div>
}
  • 类组件
function Father() {
  return (
    <Son></Son>
  );
}

class Son extends React.Component {
  static defaultProps = {
    name: '孤城浪人'
  }
  render() {
    return <div>{this.props.name}</div>
  }
}

函数组件

函数组件接收一个参数就是 props,当然作为形参可以任意命名,但是一般参数名就是 props。

<body>
  <div id="root"></div>
  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script type="text/babel">
    // 渲染虚拟dom
    function Father() {
      return (
        <div>
          <Son myKey="姓名" value="孤城浪人" />
          <Son myKey="年龄" value="22" />
        </div>
      )
    }
    function Son(props) {
      return <div>{props.myKey}{props.value}</div>
    }
    ReactDOM.render(<Father />, document.getElementById('root'));
  </script>
</body>

类组件

类组件会自动将 props 绑定在当前组件实例上。

<body>
  <div id="root"></div>
  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script type="text/babel">
    // 渲染虚拟dom
    class Father extends React.Component {
      state = {
        info: [{
          myKey: '姓名',
          value: '孤城浪人'
        }, {
          myKey: '年龄',
          value: '22'
        }]
      }
      render() {
        return (
          <div>
            {this.state.info.map(item => <Son key={item.value} myKey={item.myKey} value={item.value} />)}
          </div>
        )
      }
    }
    class Son extends React.Component {
      render() {
        return <div>{this.props.myKey}{this.props.value}</div>
      }
    }
    ReactDOM.render(<Father />, document.getElementById('root'));
  </script>
</body>

子传父

上面说过子组件不能直接修改父组件传来的 props,并且父组件中数据改变后子组件自动接收更新后的数据,利用这两个特性 React 提供了一种机制间接的修改。父组件传给子组件一个函数,该函数能够修改父组件的数据,当子组件需要修改数据时,就调用该函数,让父组件帮自己改,最后自动接收修改后的数据。

步骤

  1. 父组件提供回调函数,通过 props 传递给子组件
  2. 子组件调用 props 中的回调函数,函数可传参
  3. 父组件函数的参数就是子组件传递的数据
<body>
  <div id="root"></div>
  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script type="text/babel">
    // 渲染虚拟dom
    class Father extends React.Component {
      state = {
        info: [{
          myKey: '姓名',
          value: '孤城浪人'
        }, {
          myKey: '年龄',
          value: 22
        }]
      }
      addAge = () => {
        this.setState(preState => {
          console.log(preState)
          preState.info.forEach(element => {
            if (element.myKey == '年龄') {
              element.value++;
            }
          });
          return preState;
        });
      }
      render() {
        return (
          <div>
            <Son myKey={this.state.info[0].myKey} value={this.state.info[0].value} />
            <Son myKey={this.state.info[1].myKey} value={this.state.info[1].value} addAge={this.addAge} />
          </div>
        )
      }
    }
    class Son extends React.Component {
      render() {
        return <div onClick={this.props.addAge}>{this.props.myKey}{this.props.value}</div>
      }
    }
    ReactDOM.render(<Father />, document.getElementById('root'));
  </script>
</body>

兄弟组件通信

开发中需要通信的组件之间当然不只是父子关系,还有兄弟关系,如下图子组件1和子组件2。
在这里插入图片描述
我们可以子组件 1 和子组件 2 都用到的数据保存在父组件中,在通过 props 传给子组件,这样无论是子组件 1 还是子组件 2 通过父子通信的方式修改了数据,子组件都能接收到修改后的数据。

<body>
  <div id="root"></div>
  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script type="text/babel">
    class Father extends React.Component {
      state = {
        myKey: '年龄',
        value: 22
      }
      addAge = () => {
        this.setState(preState => preState.value++);
      }
      render() {
        return (
          <div>
            <Son1 myKey={this.state.myKey} value={this.state.value} addAge={this.addAge} />
            <Son2 myKey={this.state.myKey} value={this.state.value} addAge={this.addAge} />
          </div>
        )
      }
    }
    class Son1 extends React.Component {
      render() {
        return <div onClick={this.props.addAge}>{this.props.myKey}{this.props.value}</div>
      }
    }
    class Son2 extends React.Component {
      render() {
        return <div onClick={this.props.addAge}>{this.props.myKey}{this.props.value}</div>
      }
    }
    ReactDOM.render(<Father />, document.getElementById('root'));
  </script>
</body>

祖孙组件通信

在这里插入图片描述
这种嵌套极深的组件间通信目前来说有两种方式

  • 层层传递 props
  • context 技术

层层传递实现

这种实现方式比较麻烦,而且也不利于后期维护,若是需要修改一个属性名,那么层层组件都需要修改。

<body>
  <div id="root"></div>
  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script type="text/babel">
    // 渲染虚拟dom
    class Father extends React.Component {
      state = {
        myKey: '年龄',
        value: 22
      }
      addAge = () => {
        this.setState(preState => preState.value++);
      }
      render() {
        return (
          <div>
            <Son myKey={this.state.myKey} value={this.state.value} addAge={this.addAge} />
          </div>
        )
      }
    }
    class Son extends React.Component {
      render() {
        return <Grandson addAge={this.props.addAge} myKey={this.props.myKey} value={this.props.value} />
      }
    }
    class Grandson extends React.Component {
      render() {
        return <div onClick={this.props.addAge}>{this.props.myKey}{this.props.value}</div>
      }
    }
    ReactDOM.render(<Father />, document.getElementById('root'));
  </script>
</body>

context 实现

上下文,一个范围,只要在这个范围内,就可以跨级组件通讯。(不需要 props 层层传递)。React 会往上找到最近的 theme Provider,然后使用它的值。

我的理解就是类似发布订阅模式,祖辈组件发布数据,孙辈组件订阅数据(个人理解)。

<body>
  <div id="root"></div>
  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script type="text/babel">
    const infoContext = React.createContext({});
    class Father extends React.Component {
      state = {
        myKey: '年龄',
        value: 22,
      }
      addAge = () => {
        this.setState(preState => preState.value++);
      }
      render() {
        return (
          <infoContext.Provider value={this.state}>
            <div>
              <Son />
            </div>
          </infoContext.Provider>

        )
      }
    }
    class Son extends React.Component {
      render() {
        return <Grandson />
      }
    }
    class Grandson extends React.Component {
      // 指定 contextType 读取当前的 theme context。这是不能少的
      static contextType = infoContext;
      render() {
        console.log(this.context)
        return <div onClick={this.context.addAge()}>{this.context.myKey}{this.context.value}</div>
      }
    }
    ReactDOM.render(<Father />, document.getElementById('root'));
  </script>
</body>

第三方库

除了上述的几种组件间通信方式还可以使用第三方插件例如 redux,我的理解就是他们提供一个仓库,存放着所有的需要共享的数据,任何组件都可以从这个仓库拿数据、修改数据。如下图
在这里插入图片描述
但是这里就不做过多记录,后边学习到这些知识在记录一下。我是孤城浪人,一名正在前端路上摸爬滚打的菜鸟,欢迎你的关注。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值