React生命周期与父子组件间通信知识点详细讲解

目录
  • 声明周期
  • 声明周期解析
  • 生命周期函数
  • Constructor
  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount
  • 不常用的生命周期函数
  • 认识组件间的通信
  • 参数propTypes
  • 限制单个元素
  • 默认 Prop 值
  • 对于函数式组件
  • 子组件传递父组件

声明周期

很多的事物都有从创建到销毁的整个过程,这个过程称之为是生命周期;

React组件也有自己的生命周期,了解组件的生命周期可以让我们在最合适的地方完成自己想要的功能;

生命周期和生命周期函数的关系:

生命周期是一个抽象的概念,在生命周期的整个过程,分成了很多个阶段;

比如装载阶段(Mount),组件第一次在DOM树中被渲染的过程;

比如更新过程(Update),组件状态发生变化,重新更新渲染的过程;

比如卸载过程(Unmount),组件从DOM树中被移除的过程;

React内部为了告诉我们当前处于哪些阶段,会对我们组件内部实现的某些函数进行回调,这些函数就是生命周期函数:

比如实现componentDidMount函数:组件已经挂载到DOM上时,就会回调;

比如实现componentDidUpdate函数:组件已经发生了更新时,就会回调;

比如实现componentWillUnmount函数:组件即将被移除时,就会回调;

我们可以在这些回调函数中编写自己的逻辑代码,来完成自己的需求功能;

我们谈React生命周期时,主要谈的类的生命周期,因为函数式组件是没有生命周期函数的

声明周期解析

我们先来了解一下最基础、最常用的生命周期函数:

生命周期函数

class HelloWorld extends React.Component {
  // 1.构造方法: constructor
  constructor() {
    console.log("HelloWorld constructor")
    super()
    this.state = {
      message: "Hello World"
    }
  }
  changeText() {
    this.setState({ message: "你好啊, 李银河" })
  }
  // 2.执行render函数
  render() {
    console.log("HelloWorld render")
    const { message } = this.state
    return (
      <div>
        <h2>{message}</h2>
        <p>{message}是程序员的第一个代码!</p>
        <button onClick={e => this.changeText()}>修改文本</button>
      </div>
    )
  }
  // 3.组件被渲染到DOM: 被挂载到DOM
  componentDidMount() {
    console.log("HelloWorld componentDidMount")
  }
  // 4.组件的DOM被更新完成: DOM发生更新
  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log("HelloWorld componentDidUpdate:", prevProps, prevState, snapshot)
  }
  // 5.组件从DOM中卸载掉: 从DOM移除掉
  componentWillUnmount() {
    console.log("HelloWorld componentWillUnmount")
  }
  // 不常用的生命周期补充
  shouldComponentUpdate() {
    return true
  }
  getSnapshotBeforeUpdate() {
    console.log("getSnapshotBeforeUpdate")
    return {
      scrollPosition: 1000
    }
  }
}

Constructor

如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。

constructor中通常只做两件事情:

通过给 this.state 赋值对象来初始化内部的state;

为事件绑定实例(this);

componentDidMount

componentDidMount() 会在组件挂载后(插入 DOM 树中)立即调用。

componentDidMount中通常进行哪里操作呢?

依赖于DOM的操作可以在这里进行;

在此处发送网络请求就最好的地方;(官方建议)

可以在此处添加一些订阅(会在componentWillUnmount取消订阅);

componentDidUpdate

componentDidUpdate() 会在更新后会被立即调用,首次渲染不会执行此方法。

当组件更新后,可以在此处对 DOM 进行操作;

如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求;(例如,当 props 未发生变化时,则不会执行网络请求)。

componentWillUnmount

componentWillUnmount() 会在组件卸载及销毁之前直接调用。

在此方法中执行必要的清理操作;

例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等;

不常用的生命周期函数

除了上面介绍的生命周期函数之外,还有一些不常用的生命周期函数:

getDerivedStateFromProps:state 的值在任何时候都依赖于 props时使用;该方法返回一个对象来更新state;

getSnapshotBeforeUpdate:在React更新DOM之前回调的一个函数,可以获取DOM更新前的一些信息(比如说滚动位置);

shouldComponentUpdate:该生命周期函数很常用,但是我们等待讲性能优化时再来详细讲解;

另外,React中还提供了一些过期的生命周期函数,这些函数已经不推荐使用。

认识组件间的通信

在开发过程中,我们会经常遇到需要组件之间相互进行通信:

比如App可能使用了多个Header,每个地方的Header展示的内容不同,那么我们就需要使用者传递给Header一些数据,让其进行展示;

又比如我们在Main中一次性请求了Banner数据和ProductList数据,那么就需要传递给他们来进行展示;

也可能是子组件中发生了事件,需要由父组件来完成某些操作,那就需要子组件向父组件传递事件;

总之,在一个React项目中,组件之间的通信是非常重要的环节;

父组件在展示子组件,可能会传递一些数据给子组件:

父组件通过 属性=值 的形式来传递给子组件数据;

子组件通过 props 参数获取父组件传递过来的数据;

参数propTypes

对于传递给子组件的数据,有时候我们可能希望进行验证,特别是对于大型项目来说:

当然,如果你项目中默认继承了Flow或者TypeScript,那么直接就可以进行类型验证;

但是,即使我们没有使用Flow或者TypeScript,也可以通过 prop-types 库来进行参数验证;

从 React v15.5 开始,React.PropTypes 已移入另一个包中:prop-types 库

import PropTypes from 'prop-types';
MyComponent.propTypes = {
  // 你可以将属性声明为 JS 原生类型,默认情况下
  // 这些属性都是可选的。
  optionalArray: PropTypes.array,
  optionalBool: PropTypes.bool,
  optionalFunc: PropTypes.func,
  optionalNumber: PropTypes.number,
  optionalObject: PropTypes.object,
  optionalString: PropTypes.string,
  optionalSymbol: PropTypes.symbol,
  // 任何可被渲染的元素(包括数字、字符串、元素或数组)
  // (或 Fragment) 也包含这些类型。
  optionalNode: PropTypes.node,
  // 一个 React 元素。
  optionalElement: PropTypes.element,
  // 一个 React 元素类型(即,MyComponent)。
  optionalElementType: PropTypes.elementType,
  // 你也可以声明 prop 为类的实例,这里使用
  // JS 的 instanceof 操作符。
  optionalMessage: PropTypes.instanceOf(Message),
  // 你可以让你的 prop 只能是特定的值,指定它为
  // 枚举类型。
  optionalEnum: PropTypes.oneOf(['News', 'Photos']),
  // 一个对象可以是几种类型中的任意一个类型
  optionalUnion: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.instanceOf(Message)
  ]),
  // 可以指定一个数组由某一类型的元素组成
  optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
  // 可以指定一个对象由某一类型的值组成
  optionalObjectOf: PropTypes.objectOf(PropTypes.number),
  // 可以指定一个对象由特定的类型值组成
  optionalObjectWithShape: PropTypes.shape({
    color: PropTypes.string,
    fontSize: PropTypes.number
  }),
  // An object with warnings on extra properties
  optionalObjectWithStrictShape: PropTypes.exact({
    name: PropTypes.string,
    quantity: PropTypes.number
  }),
  // 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保
  // 这个 prop 没有被提供时,会打印警告信息。
  requiredFunc: PropTypes.func.isRequired,
  // 任意类型的必需数据
  requiredAny: PropTypes.any.isRequired,
  // 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
  // 请不要使用 `console.warn` 或抛出异常,因为这在 `oneOfType` 中不会起作用。
  customProp: function(props, propName, componentName) {
    if (!/matchme/.test(props[propName])) {
      return new Error(
        'Invalid prop `' + propName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  },
  // 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。
  // 它应该在验证失败时返回一个 Error 对象。
  // 验证器将验证数组或对象中的每个值。验证器的前两个参数
  // 第一个是数组或对象本身
  // 第二个是他们当前的键。
  customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
    if (!/matchme/.test(propValue[key])) {
      return new Error(
        'Invalid prop `' + propFullName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  })
};

限制单个元素

你可以通过 PropTypes.element 来确保传递给组件的 children 中只包含一个元素。

import PropTypes from 'prop-types';
class MyComponent extends React.Component {
  render() {
    // 这必须只有一个元素,否则控制台会打印警告。
    const children = this.props.children;
    return (
      <div>
        {children}
      </div>
    );
  }
}
MyComponent.propTypes = {
  children: PropTypes.element.isRequired
};

默认 Prop 值

您可以通过配置特定的 defaultProps 属性来定义 props 的默认值:

class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}
// 指定 props 的默认值:
Greeting.defaultProps = {
  name: 'Stranger'
};
// 渲染出 "Hello, Stranger":
const root = ReactDOM.createRoot(document.getElementById('example'));
root.render(<Greeting />);

从 ES2022 开始,你也可以在 React 类组件中将 defaultProps 声明为静态属性。这种现代语法需要添加额外的编译步骤才能在老版浏览器中工作。

class Greeting extends React.Component {
  static defaultProps = {
    name: 'stranger'
  }
  render() {
    return (
      <div>Hello, {this.props.name}</div>
    )
  }
}

defaultProps 用于确保 this.props.name 在父组件没有指定其值时,有一个默认值。propTypes 类型检查发生在 defaultProps 赋值后,所以类型检查也适用于 defaultProps

对于函数式组件

如果你在常规开发中使用函数组件,那你可能需要做一些适当的改动,以保证 PropsTypes 应用正常。

假设你有如下组件:

export default function HelloWorldComponent({ name }) {
  return (
    <div>Hello, {name}</div>
  )
}

如果要添加 PropTypes,你可能需要在导出之前以单独声明的一个函数的形式,声明该组件,具体代码如下:

function HelloWorldComponent({ name }) {
  return (
    <div>Hello, {name}</div>
  )
}
export default HelloWorldComponent

接着,可以直接在 HelloWorldComponent 上添加 PropTypes:

import PropTypes from 'prop-types'
function HelloWorldComponent({ name }) {
  return (
    <div>Hello, {name}</div>
  )
}
HelloWorldComponent.propTypes = {
  name: PropTypes.string
}
export default HelloWorldComponent

子组件传递父组件

某些情况,我们也需要子组件向父组件传递消息:

在vue中是通过自定义事件来完成的;

在React中同样是通过props传递消息,只是让父组件给子组件传递一个回调函数,在子组件中调用这个函数即可;

我们这里来完成一个案例:

将计数器案例进行拆解;

将按钮封装到子组件中:CounterButton;

CounterButton发生点击事件,将内容传递到父组件中,修改counter的值;

app.jsx

import React, { Component } from 'react'
import AddCounter from './AddCounter'
import SubCounter from './SubCounter'
export class App extends Component {
  constructor() {
    super()
    this.state = {
      counter: 100
    }
  }
  changeCounter(count) {
    this.setState({ counter: this.state.counter + count })
  }
  render() {
    const { counter } = this.state
    return (
      <div>
        <h2>当前计数: {counter}</h2>
        <AddCounter addClick={(count) => this.changeCounter(count)}/>
        <SubCounter subClick={(count) => this.changeCounter(count)}/>
      </div>
    )
  }
}
export default App

subCounter.jsx

import React, { Component } from 'react'
export class SubCounter extends Component {
  subCount(count) {
    this.props.subClick(count)
  }
  render() {
    return (
      <div>
        <button onClick={e => this.subCount(-1)}>-1</button>
        <button onClick={e => this.subCount(-5)}>-5</button>
        <button onClick={e => this.subCount(-10)}>-10</button>
      </div>
    )
  }
}
export default SubCounter

addCounter.jsx

import React, { Component } from 'react'
// import PropTypes from "prop-types"
export class AddCounter extends Component {
  addCount(count) {
    this.props.addClick(count)
  }
  render() {
    return (
      <div>
        <button onClick={e => this.addCount(1)}>+1</button>
        <button onClick={e => this.addCount(5)}>+5</button>
        <button onClick={e => this.addCount(10)}>+10</button>
      </div>
    )
  }
}
// AddCounter.propTypes = {
//   addClick: PropTypes.func
// }
export default AddCounter

到此这篇关于React生命周期与父子组件间通信知识点详细讲解的文章就介绍到这了,更多相关React生命周期内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • React中的生命周期详解

    目录 react生命周期 常用的生命周期 不常用的生命周 完整的生命周期图 react生命周期 函数组件无生命周期,生命周期只有类组件才拥有 生命周期函数指在某一时刻组件会自动调用并执行的函数. React每个类组件都包含生命周期方法,以便于在运行过程中特定的阶段执行这些方法. 例如:我们希望在第一次将其呈现到DOM时设置一个计时器Clock.这在React中称为“安装”.我们也想在删除由产生 的DOM时清除该计时器Clock.这在React中称为“卸载”. 一般分为:挂载.更新.卸载 常用的生

  • React 组件的常用生命周期函数汇总

    目录 1. 概述 2. 生命周期的三个阶段 2.1. 创建时(挂载阶段) 2.2. 更新时(更新阶段) 2.3. 卸载时(卸载阶段) 1. 概述 意义:组件的生命周期有助于理解组件的运行方式.完成更复杂的组件功能.分析组件错误原因等. 组件的生命周期:组件从被创建到挂载到页面中运行,再到组件不用时卸载的过程. 生命周期的每个阶段总是伴随着一些方法调用,这些方法就是生命周期的钩子函数. 钩子函数的作用:为开发人员在不同阶段操作组件提供了时机. 只有类组件才有生命周期. 2. 生命周期的三个阶段 每

  • React的生命周期函数初始挂载更新移除详解

    目录 概述 constructor 初始 挂载 更新 移除 概述 在React中,生命周期函数指的是组件在某一个时刻会自动执行的函数 constructor 在类或组件创建的时候被自动执行,我们可以说它是生命周期函数,但它并不是React所特有的,所有的Es6对象都有这个函数,所以并不能说它是React的生命周期函数 初始 当数据发生变化时,render函数会被自动执行,符合我们对React生命周期函数的定义,所以它是React的生命周期函数,但在初始阶段,并不会有任何的React生命周期函数被

  • React生命周期函数深入全面介绍

    目录 1. 注意 2. 图解 3. 生命周期函数 3.1 constructor构造函数 3.2 static getDerivedStateFromProps(nextProps, prevState)方法 3.3 挂载时和更新时的生命周期函数执行顺序 3.4 componentWillUnmount函数的使用 3.5 shouldComponentUpdate优化渲染方案 1. 注意 函数组件无生命周期,生命周期只有类组件才拥有. 2. 图解 完整的生命周期主要为三个部分,分别为挂载时.更新

  • React中父子组件通信详解

    目录 父组件向子组件通信 存在期 父组件向子组件通信 在父组件中,为子组件添加属性数据,即可实现父组件向子组件通信.传递的数据可以分成两类 子组件是作为属性来接收这些数据的 第一类就是数据:变量,对象,属性数据,状态数据等等 这些数据发生改变,子组件接收的属性数据就发生了改变. 第二类就是方法:父组件可以向子组件传递属性方法,子组件接收方法,并可以在组件内执行,有两种执行方式 注意:父组件传给子组件的方法是不能执行的,执行了相当于将方法的返回值传递给子组件. 第一种 作为事件回调函数执行 参数默

  • React中的生命周期和子组件

    目录 组件生命周期 创建创建期 获取虚拟DOM 子组件 组件生命周期 为了说明组件的创建,存在,销毁的过程,react提供了组件的生命周期,共分三大周期: 创建期:说明组件的创建的过程,相当于人的少年 存在期:说明组件的存在的过程,相当于人的中年 销毁期:说明组件的销毁的过程,相当于人的老年 创建创建期 创建期共分五个阶段: ES5开发中,对应五个方法:getDefaultProps,getInitialsate, ​​componentWillMount​​, ​​render​​, ​​co

  • React State与生命周期详细介绍

    目录 一.State 1.1 类组件中的State 1.2 函数组件中的State 二.React生命周期 2.1 挂载 2.2 更新 2.3 卸载 2.4 函数式组件useEffect 三.总结 一.State 在React当中,当你更新组件的state,然后新的state就会重新渲染到页面中.在这个时候不需要你操作任何DOM.这和vue中组件的data中的数据是相似的. 1.1 类组件中的State <!DOCTYPE html> <html lang="en"&

  • React 父子组件通信的实现方法

    通讯是单向的,数据必须是由一方传到另一方. 1.父组件与子组件间的通信. 在 React 中,父组件可以向子组件通过传 props 的方式,向子组件进行通讯. 父组件 App.js import React, { Component } from 'react'; import './App.css'; import Child from './child' class App extends Component { constructor(props){ super(props); this.

  • React生命周期与父子组件间通信知识点详细讲解

    目录 声明周期 声明周期解析 生命周期函数 Constructor componentDidMount componentDidUpdate componentWillUnmount 不常用的生命周期函数 认识组件间的通信 参数propTypes 限制单个元素 默认 Prop 值 对于函数式组件 子组件传递父组件 声明周期 很多的事物都有从创建到销毁的整个过程,这个过程称之为是生命周期: React组件也有自己的生命周期,了解组件的生命周期可以让我们在最合适的地方完成自己想要的功能: 生命周期和

  • vue之父子组件间通信实例讲解(props、$ref、$emit)

    组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.那么组件间如何通信,也就成为了vue中重点知识了.这篇文章将会通过props.$ref和 $emit 这几个知识点,来讲解如何实现父子组件间通信. 在说如何实现通信之前,我们先来建两个组件father.vue和child.vue作为示例的基础. //父组件 <template> <div> <h1>我是父组件!</h1> <child>

  • vue2.0父子组件间通信的实现方法

    1.父组件传递数据给子组件 父组件数据如何传递给子组件呢?可以通过props属性来实现 父组件: <parent> <child :child-msg="msg"></child>//这里必须要用 - 代替驼峰 </parent> data(){ return { msg: [1,2,3] };} 子组件通过props来接收数据: 方式1: props: ['childMsg'] 方式2 : props: { childMsg: Arra

  • Vue 父子组件、组件间通信

    本人对Vue组件间通信不懂,搜索了很多关于Vue 父子组件间通信介绍,下面我来记录一下,有需要了解Vue 父子组件.组件间通信的朋友可参考.希望此文章对各位有所帮助. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>组件</title> <meta name="viewport"

  • react生命周期(类组件/函数组件)操作代码

    1.react代码模式分为两种 类组件和函数组件(生命周期也有所不同) 2.类组件(写法如下) import React from 'react' export default class App1 extends React.Component{ state = { username:'', password:'' } setUser = (event) => { this.setState({username:event.target.value}) } setPass = (event)

  • Vue如何实现组件间通信

    1. 父子间通信 最常见的就是父子之间的通信,通信是双向的数据传递. 1.1 父组件 --> 儿子组件 父组件向儿子组件传递数据的方式就是 通过 Prop 向子组件传递数据. //child.vue <template> <div> 我是儿子,我收到来自父亲的数据为 {{value}} </div> </template> <script> export default { props:{ value: String } } //App.v

  • React组件间通信的三种方法(简单易用)

    目录 一.父子组件通信 二.跨级组件通信 1.逐层传值 2.跨级传值 三.兄弟(无嵌套)组件通信 四.路由传值 五.Redux React知识中一个主要内容便是组件之间的通信,以下列举几种常用的组件通信方式,结合实例,通俗易懂,建议收藏. 一.父子组件通信 原理:父组件通过props(与vue中的props区分开)向子组件通信,子组件通过回调事件与父组件通信. 首先,先创建一个父组件Parent.js跟子组件Children.js,二者的关系为直接父子关系. Parent.js父组件如下,给父组

  • Vue组件间通信方法总结(父子组件、兄弟组件及祖先后代组件间)

    前言 除了使用 Vuex 方法外,vue 提供了各种各样的组件间通信的方案.文章整理一下父子组件.兄弟组件.祖先后代组件间是如何通信的.

  • 详解Angualr 组件间通信

    Angualr 组件间通信 约定: 遵循Angular官方的说法,下文中的AngularJS代指1.x版本,Angular代指Angular2及以后的升级版本. 采用Angular(或者任意MV*)的前端框架开发单页应用(SPA)时,我们都可能会遇见如下的场景: A组件和B组件之前需要相互通信,或是A路由状态需要知道B路由状态的信息等等业务需求. 这个时候就需要设计到采用一套合理的通信方案来解决数据同步,数据通信的问题. AngularJS 组件间的数据通信 在AngularJS中,也就是Ang

随机推荐