React 学习笔记:组件通信

news2024/12/24 21:23:11

组件通信

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

父传子

在这里插入图片描述

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,我的理解就是他们提供一个仓库,存放着所有的需要共享的数据,任何组件都可以从这个仓库拿数据、修改数据。如下图
在这里插入图片描述
但是这里就不做过多记录,后边学习到这些知识在记录一下。我是孤城浪人,一名正在前端路上摸爬滚打的菜鸟,欢迎你的关注。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/80692.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习入门(五十九)循环神经网络——通过时间反向传播

深度学习入门&#xff08;五十九&#xff09;循环神经网络——通过时间反向传播前言循环神经网络——通过时间反向传播教材1 循环神经网络的梯度分析1.1 完全计算1.2 截断时间步1.3 随机截断1.4 比较策略2 通过时间反向传播的细节3 小结前言 核心内容来自博客链接1博客连接2希…

基于java+springboot+vue+mysql的甜品蛋糕销售商城网站

项目介绍 随着社会的快速发展&#xff0c;计算机的影响是全面且深入的。人们生活水平的不断提高&#xff0c;日常生活中用户对网上蛋糕商城方面的要求也在不断提高&#xff0c;网上蛋糕商城得到广大用户的青睐&#xff0c;使得网上蛋糕商城的开发成为必需而且紧迫的事情。本系…

Docker笔记--使用数据卷实现容器与宿主机的数据交互

1--数据卷的介绍和作用 在 Docker 架构中&#xff0c;宿主机系统和容器之间不能直接传递数据&#xff0c;同时当容器被删除时&#xff0c;容器所有的数据都会被清除&#xff1b; 数据卷能够在宿主机与容器、容器与容器之间搭建数据传输和共享的通道&#xff0c;当容器内的目录与…

C++ 快速复习-数据类型

内置数据类型 int、unsigned int 、long、unsigned long 、short、char、signed char、bool、 long long float、double、long double 等 无符号的数据类型 主要在于 不在区分 -&#xff0c;数据波动范围变大。另外&#xff0c;值得注意的是 unsigned 类型的数据 不建议在输出…

玩以太坊链上项目的必备技能(变量作用域-Solidity之旅五)

在前文我们讲过 Solidity 是一种静态类型的语言&#xff0c;这就意味着在声明变量前需先指定类型。 而 Solidity 对变量划分了以下三种作用域范围&#xff1a; 状态变量&#xff08;State Variable&#xff09;&#xff1a; ​ 该变量的值被永久地存放在合约存储中&#xff…

JS新年倒计时

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;前端案例分…

Java---线程详解

目录 一、线程的介绍 二、线程的使用 &#xff08;1&#xff09;多线程的实现 1&#xff1a;继承Thread类 2&#xff1a;实现Runnable接口 &#xff08;2&#xff09;设置和获取线程名称 1:继承Thread类 2&#xff1a;实现Runnable接口 &#xff08;3&#xff09;线程…

Java学习—多线程Thread

多线程1. 线程简介1.1 普通方法和多线程1.2 程序、进程、线程2. 线程创建2.1 Thread类案例&#xff1a;下载图片2.2 Runnable接口案例&#xff1a;龟兔赛跑2.3 Callable接口3. 静态代理4. Lamda表达式5. 线程状态5.1 线程方法5.2 停止线程5.3 线程休眠5.4 线程礼让-yield5.5 Jo…

揭秘SpringMVC-DispatcherServlet之九大组件(二)

前言 上回聊到了HandlerAdapter&#xff0c;今天继续聊后面的组件。今天的主角是HandlerMapping&#xff0c;这篇文章全为他服务了。 HandlerMapping 上回说的Handler&#xff0c;我们说是处理特定请求的。也就是说&#xff0c;不是所有的请求都能处理。那么问题来了&#x…

gateway初始化与配置

1、排除依赖 spring-boot-starter-webflux 2、添加依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency><groupId>org.springf…

基于GDAL的JAVA生成GDB文件实战

前言 在之前博客中&#xff0c;陆续的介绍了关于gdb文件的读取&#xff0c;gis利器之Gdal&#xff08;三&#xff09;gdb数据读取&#xff0c;玩转GDAL一文带你深入Windows下FileGDB驱动支持&#xff0c;这些文章主要都是介绍gdal的读取gdb以及简单的gdb文件读写。在实际工作中…

VJ个人周赛

A:模拟 题意&#xff1a;给定了N个任务&#xff0c;每个任务都有一个优先级&#xff08;1~9&#xff09;&#xff0c;数字越大&#xff0c;优先级越高。将这些任务放入队列中&#xff0c;如果出队的元素&#xff08;x&#xff09;&#xff0c;x的优先级不是最高的&#xff0c;那…

从高级测试到测试开发有什么感悟

最近加入了新的团队&#xff0c;角色发生较大的转变&#xff0c;在这里分享一下自己的感受。 测试的划分 如果我们把产品的生产看成一个流水线的话&#xff0c;那么测试就是流水线上的一个重要岗位&#xff0c;把控着产品的质量。 当然&#xff0c;产品类型的不同&#xff0…

信息系统安全管理

信息系统安全是一个绕不开的话题。从事IT行业&#xff0c;不论何种角色&#xff0c;哪个工种&#xff0c;都需要有所了解。 一、信息系统安全策略 1、概述 信息系统安全策略是指对&#xff08;本单位&#xff09;信息系统的安全风险&#xff08;安全威胁&#xff09;进行有效…

小白学编程(js):通过按钮变换背景颜色

《JavaScript从入门到精通》【例9.1】 代码演示&#xff1a; <body><form class"form1" action"" name"form1" method"psot"><p><input type"button" name"Submit" value"变换背景&qu…

[附源码]计算机毕业设计基于Java的图书购物商城Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Linux常用环境配置及软件安装(持续更新)

1、jdk 1、下载jdk Linux安装包 把安装包放到自己定义的目录下 安装包网盘 提取码&#xff1a;n5hj 2、解压 解压安装包&#xff0c;输入命令&#xff1a; tar -xvf jdk-8u221-linux-x64.tar.gz 解压完成后会生成一个新文件 3、配置环境变量 编辑profile文件 vim /etc/p…

基于java+springboot+mybatis+vue+mysql的高校党务系统

项目介绍 本党务管理系统主要包括五大功能模块&#xff0c;即管理员模块、学生模块、积极分子模块、党员、党建组织。 &#xff08;1&#xff09;管理员模块&#xff1a;主要功能有&#xff1a;首页、个人中心、学生管理、学院管理、专业管理、班级管理、积极分子管理、党员管…

LeetCode HOT 100 —— 208. 实现 Trie (前缀树)

题目 Trie&#xff08;发音类似 “try”&#xff09;或者说 前缀树 是一种树形数据结构&#xff0c;用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景&#xff0c;例如自动补完和拼写检查。 请你实现 Trie类&#xff1a; Trie() 初始化前缀树对象。 vo…

postgresql_internals学习笔记(二)常规vacuum

一、 作用与原理 page pruning执行速度很快&#xff0c;但它们的作用范围毕竟只有单页、且不包含索引&#xff0c;因此&#xff0c;我们还需要更有效的清理机制。 常规vacuum是最常用的一种&#xff0c;作用范围可以是整张表&#xff0c;清理过期元组及索引项&#xff0c;并且不…