IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React 的组件通信与生命周期 -> 正文阅读

[JavaScript知识库]React 的组件通信与生命周期

一.组件通信

React组件间通信常见的几种情况:

  • 父组件向子组件通信
  • 子组件向父组件通信
  • 跨级组件通信
  • 非嵌套关系的组件通信

React中的数据进行通信方式

  • 在React中数据是从上自下流动(传递)的,也就是一个父组件可以把它的 state / props 通过 props 传递给它的子组件,但是子组件不能修改 props

  • React.js 是单向数据流,如果子组件需要修改父组件状态(数
    据),是通过回调函数方式来完成的

1. 父子组件的通信方式?

父组件向子组件通信:父组件通过 props 向子组件传递需要的信息。

子组件向父组件通信:在父级中定义相关的数据操作方法(或其他回调), 把该方法传递给子级,在子级中调用该方法父级传递消息

// 子组件: Child
const Child = props =>{
  return <p>{props.name}</p>
}
// 父组件 Parent
const Parent = ()=>{
    return <Child name="react"></Child>
}

子组件向父组件通信:: props+回调的方式。

// 子组件: Child
const Child = props =>{
  const cb = msg =>{
      return ()=>{
          props.callback(msg)
      }
  }
  return (
      <button onClick={cb("你好!")}>你好</button>
  )
}
// 父组件 Parent
class Parent extends Component {
    callback(msg){
        console.log(msg)
    }
    render(){
        return <Child callback={this.callback.bind(this)}></Child>    
    }
}

2. 跨级组件的通信方式?

作用:就是让它所包裹的内容都可以接收到它的参数
父组件向子组件的子组件通信,向更深层子组件通信:

  • 使用props,利用中间组件层层传递,但是如果父组件结构较深,那么中间每一层组件都要去传递props,增加了复杂度,并且这些props并不是中间组件自己需要的。

  • 使用context,context相当于一个大容器,可以把要通信的内容放在这个容器中,这样不管嵌套多深,都可以随意取用,对于跨越多层的全局数据可以使用context实现。

创建一个context.js文件

import {createContext} from 'react'
// createContext是一个方法
let context=createContext()
// 它有两个返回值 一个传值(Provider)一个接收(Consumer)
let { Consumer, Provider}=context
// 导出
export default context
export {Consumer, Provider}

在父组件中传递,使用createContext中的返回值Provider传递参数

import React,{Component} from 'react'
import Childrens from './childrens'
// 需要调用 Provider 传递数据 它是一个标签
import {Provider} from './content'
export default class App extends Component{
    state={
        name:'小明',
        sex:'男'
    }
    parentValue=(newName)=>{
        this.setState({
            name:newName
        })
    }
    render(){
        let {sex}=this.state
        // </Provider>标签包裹后它里面的所有内容都能拿到它传的参数
        return (<Provider value={
           { info:'哈喽'}
        }>
            <div>    
                <p>{this.state.name}</p>
                <Childrens
                content={sex}
                parentValue={this.parentValue}
        />
        </div>
        </Provider>
        )
    }
}

在子组件使用使用createContext中的返回值Consumer接收

import React,{Component} from 'react'
import {Consumer} from './content'
export default class childrens extends Component{
    render(){
        let {Fragment}=React
        let {parentValue}=this.props
        return (<Fragment>
            <button onClick={
                ()=>{
                    parentValue('hah1')
                }
            }>点击</button>
            <p>
                {/* 把通过Provider传递过来的参数接收到 然后在页面上显示出来 */}
                <Consumer>{(value)=>value.info}</Consumer>
            </p>
        </Fragment>)
    }
}

3. 组件通信的方式有哪些

父组件向?组件通讯: ?组件可以向?组件通过传 props 的?式,向?组件进?通讯

子组件向?组件通讯: props+回调的?式,?组件向?组件传递props进?通讯,此props为作?域为?组件?身的函 数,?组件调?该函数,将?组件想要传递的信息,作为参数,传递到?组件的作?域中

兄弟组件通信: 找到这两个兄弟节点共同的?节点,结合上?两种?式由?节点转发信息进?通信

跨层级通信: Context 设计?的是为了共享那些对于?个组件树??是“全局”的数据,例如当前认证的?户、主题或?选语?,对于跨越多层的全局数据通过 Context 通信再适合不过

发布订阅模式: 发布者发布事件,订阅者监听事件并做出反应,我们可以通过引?event模块进?通信

全局状态管理?具: 借助Redux或者Mobx等全局状态管理?具进?通信,这种?具会维护?个全局状态中?Store,并根据不同的事件产?新的状态

二.非受控组件和受控组件

1.非受控组件

如果一个表单组件没有value props(单选和复选按钮对应的是checked props)时,就可以称为非受控组件。在非受控组件中,可以使用一个ref来从DOM获得表单值。而不是为每个状态更新编写一个事件处理程序。

类似于单项数据绑定 只可以数据改变视图

2.受控组件

在使用表单来收集用户输入时,例如等元素都要绑定一个change事件,当表单的状态发生变化,就会触发onChange事件,更新组件的state。这种组件在React中被称为受控组件,在受控组件中,组件渲染出的状态与它的value或checked属性相对应,react通过这种方式消除了组件的局部状态,使整个状态可控。react官方推荐使用受控表单组件。

受控组件更新state的流程:

可以通过初始state中设置表单的默认值
每当表单的值发生变化时,调用onChange事件处理器
事件处理器通过事件对象e拿到改变后的状态,并更新组件的state
一旦通过setState方法更新state,就会触发视图的重新渲染,完成表单组件的更新
受控组件缺陷:

表单元素的值都是由React组件进行管理,当有多个输入框,或者多个这种组件时,如果想同时获取到全部的值就必须每个都要编写事件处理函数,这会让代码看着很臃肿,所以为了解决这种情况,出现了非受控组件。

类似于 vue 的双向数据绑定 数据和视图之间可以相互影响

import React,{Component} from 'react'
//count是这个组件的名字
export default class count extends Component{
    state={
        info:'这是个值'
    }
    render(){
        let {info}=this.state
        return (
            <div>

                {/* 这里的input无论你写什么它都不会改变state中info的值 */}
                <input type='text' defaultValue={info}/>
                <input type='text' defaultValue={info}/>
                <input type='text' defaultValue={info}/>
                {/* 这里打印的一直都是上面state里面的info的值不会根据你上面input框中值变化而发生变化 */}
                <button onClick={
                    ()=>{
                        console.log(info);
                    }
                }>点击</button>
              
                <input type='text' value={info} onChange={({target})=>{
                    this.setState({
                        info:target.value
                    })
                }}/>
                {/* 这里打印的就是你input中改变的后的值 */}
                <button onClick={
                    ()=>{
                        console.log(info);
                    }
                }>受控组件</button>
            </div>
        )
    }
}

三.生命周期

生命周期流程图(新)
在这里插入图片描述

生命周期流程图(旧)
在这里插入图片描述

  • 挂载阶段
    当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:

    • constructor
    • componentWillMount
    • render
    • componentDidMount
  • 更新阶段

    • 父组件更新引起组件更新
    • componentWillReceiveProps(nextProps)
    • shouldComponentUpdate(nextProps, nextState)
    • componentWillUpdate(nextProps, nextState)
    • render
    • componentDidUpdate(prevProps, prevState)
  • 组件自身更新

    • shouldComponentUpdate
    • componentWillUpdate
    • render
    • componentDidUpdate
  • 卸载阶段
    当组件从 DOM 中移除时会调用如下方法:

    • componentWillUnmount
  • 挂载阶段

    • constructor
    • static getDerivedStateFromProps(props, state)
      • 注意 this 问题
    • render
    • componentDidMount
  • 更新阶段

    • 父组件更新引起组件更新
      当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:
      • static getDerivedStateFromProps(props, state)
      • shouldComponentUpdate()
      • componentWillUpdate()
      • render()
      • getSnapshotBeforeUpdate()
      • componentDidUpdate()
    • 组件自身更新
      • shouldComponentUpdate()
      • componentWillUpdate()
      • render()
      • getSnapshotBeforeUpdate()
      • componentDidUpdate()
  • 卸载阶段

  • componentWillUnmount

  • 错误处理
    当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法:

    • static getDerivedStateFromError()
    • componentDidCatch(error, info)

    1、constructor

    constructor 是类通用的构造函数,常用于初始化,算是生命周期的一环。React 后来的版本中类组件也可以不写。

**注意:**在构造函数中使用时,super 关键字将单独出现,并且必须在使用 this 关键字之前使用。super 关键字也可以用来调用父对象上的函数

class Test extends React.Component {
  // constructor 写法
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
    this.handleClick = this.handleClick.bind(this);
  }
  // 直接声明
  state = {
    count: 0,
  };
}

2、getDerivedStateFromProps

触发时机:state 变化、props 变化、forceUpdate,如上图。

这是一个静态方法, 是一个和组件自身"不相关"的角色. 在这个静态方法中, 除了两个默认的位置参数 nextProps 和 currentState 以外, 你无法访问任何组件上的数据。

// 初始化/更新时调用
static getDerivedStateFromProps(nextProps, currentState) {
  console.log(nextProps, currentState, "getDerivedStateFromProps方法执行");
  // 返回值是对currentState进行修改
  return {
    fatherText: nextProps.text,
  };
}

3、render
render 函数返回的 JSX 结构,用于描述具体的渲染内容, render 被调用时,它会检查 this.props 和 this.state 的变化并返回以下类型之一:

React 元素 通常通过 JSX 创建。例如,

会被 React 渲染为 DOM 节点, 会被 React 渲染为自定义组件,无论是

还是 均为 React 元素。

数组或 fragments 使得 render 方法可以返回多个元素。欲了解更多详细信息,请参阅 fragments 文档。

Portals 可以渲染子节点到不同的 DOM 子树中。欲了解更多详细信息,请参阅有关 portals 的文档

字符串或数值类型 它们在 DOM 中会被渲染为文本节点

布尔类型或 null 什么都不渲染。(主要用于支持返回 test && 的模式,其中 test 为布尔类型。)

注意: 如果 shouldComponentUpdate() 返回 false,则不会调用 render()。

Hooks 不需要写 render 函数。要注意的一点是,即使 Hooks 不需要写 render, 没有用到 React.xxx,组件内还是要import React from “react”;的(至于原因,后续深入 Hooks 学一下,大哥们也可以解释下)。React 官方也说了,后续的版本会优化掉这一点。

4、componentDidMount
主要用于组件加载完成时做某些操作,比如发起网络请求或者绑定事件。当做 vue 的 mounted 用就行了,这里需要注意的是:

componentDidMount() 里直接调用 setState()。它将触发额外渲染,也就是两次 render,不过问题不大,主要还是理解。

5、shouldComponentUpdate
该方法通过返回 true 或者 false 来确定是否需要触发新的渲染。因为渲染触发最后一道关卡,所以也是性能优化的必争之地。通过添加判断条件来阻止不必要的渲染。注意:首次渲染或使用 forceUpdate() 时不会调用该方法。

React 官方提供了一个通用的优化方案,也就是 PureComponent。PureComponent 的核心原理就是默认实现了 shouldComponentUpdate 函数,在这个函数中对 props 和 state 进行浅比较,用来判断是否触发更新。

当然 PureComponent 也是有缺点的,使用的时候一定要注意:由于进行的是浅比较,可能由于深层的数据不一致导致而产生错误的否定判断,从而导致页 面得不到更新。不适合使用在含有多层嵌套对象的 state 和 prop 中。

shouldComponentUpdate(nextProps, nextState) {
  // 浅比较仅比较值与引用,并不会对 Object 中的每一项值进行比较
  if (shadowEqual(nextProps, this.props) || shadowEqual(nextState, this.state) ) {
    return true
  }
  return false
}

6、getSnapshotBeforeUpdate
在 DOM 更新前被调用,返回值将作为 componentDidUpdate 的第三个参数。

getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log("getSnapshotBeforeUpdate方法执行");

    return "componentDidUpdated的第三个参数";
}

7、componentDidUpdate
首次渲染不会执行此方法。可以使用 setState,会触发重渲染,但一定要小心使用,避免死循环

 componentDidUpdate(preProps, preState, valueFromSnapshot) {
    console.log("componentDidUpdate方法执行");

    console.log("从 getSnapshotBeforeUpdate 获取到的值是", valueFromSnapshot);
  }

8、componentWillUnmount
主要用于一些事件的解绑,资源清理等,比如取消定时器,取消订阅事件

生命周期函数详解

constructor(props)
类的构造函数,也是组件初始化函数,一般情况下,我们会在这个阶段做一些初始化的工作

  • 初始化 state
  • 处理事件绑定函数的 this

render()

  • render 方法是 Class 组件必须实现的方法
  • static getDerivedStateFromProps(props, state)

该方法会在 render 方法之前调用,无论是挂载阶段还是更新阶段,它的存在只有一个目的:让组件在 props 变化时更新 state

componentDidMount()
在组件挂载后(render 的内容插入 DOM 树中)调用。通常在这个阶段,我们可以:

  • 操作 DOM 节点
  • 发送请求

shouldComponentUpdate(nextProps, nextState)
发生在更新阶段,getDerivedStateFromProps 之后,render 之前,该函数会返回一个布尔值,决定了后续是否执行 render,首次渲染不会调用该函数

getSnapshotBeforeUpdate(prevProps, prevState)
该方法在 render() 之前,但是在输出到 DOM 之前执行,用来获取渲染之前的快照。当我们想在当前一次更新前获取上次的 DOM 状态,可以在这里进行处理,该函数的返回值将作为参数传递给下个生命周期函数componentDidUpdate

componentDidUpdate()
该函数会在 DOM 更新后立即调用,首次渲染不会调用该方法。我们可以在这个函数中对渲染后的 DOM 进行
操作

componentWillUnmount()
该方法会在组件卸载及销毁前调用,我们可以在这里做一些清理工作,如:组件内的定时器、未完成的请求等
错误处理
当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法

  • static getDerivedStateFromError()
  • componentDidCatch()

四.总结

今天学习了组件通信 非受控组件 以及生命周期,和受控组件以及非受控组件
React的组件化极大的便利了我们的开发效率

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-28 23:15:06  更:2021-07-28 23:15:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/8 17:07:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码