当前位置:   article > 正文

React知识点总结_react父子组件生命周期执行顺序

react父子组件生命周期执行顺序

1、react 父子组件生命周期在创建和更新时的执行顺序

  旧版本
  挂载阶段:componentWillMount - render - componentDidMount
  更新阶段:componentWillReceiveProps - shouldComponentUpdate - componentWillUpdate - render - componentDidUpdate
  卸载阶段:componentWillUnmount

  新版本
挂载阶段:getDerivedStateFromProps - render - componentDidMount
  更新阶段:getDerivedStateFromProps - shouldComponentUpdate - render - getSnapShotBeforeUpdate - componentDidUpdate
  卸载阶段:componentWillUnmount

  父子组件初始化
  父组件 constructor
  父组件 getDerivedStateFromProps
  父组件 render
  子组件 constructor
  子组件 getDerivedStateFromProps
  子组件 render
  子组件 componentDidMount
  父组件 componentDidMount

  子组件修改自身state
  子组件 getDerivedStateFromProps
  子组件 shouldComponentUpdate
  子组件 render
  子组件 getSnapShotBeforeUpdate
  子组件 componentDidUpdate

  父组件修改props
  父组件 getDerivedStateFromProps
  父组件 shouldComponentUpdate
  父组件 render
  子组件 getDerivedStateFromProps
  子组件 shouldComponentUpdate
  子组件 render
  子组件 getSnapShotBeforeUpdate
  父组件 getSnapShotBeforeUpdate
  子组件 componentDidUpdate
  父组件 componentDidUpdate

  卸载子组件
  父组件 getDerivedStateFromProps
  父组件 shouldComponentUpdate
  父组件 render
  父组件 getSnapShotBeforeUpdate
  子组件 componentWillUnmount
  父组件 componentDidUpdate

https://blog.csdn.net/Dax1_/article/details/126671937

2、React 中 setState 什么时候是同步的,什么时候是异步的?

  在React中,如果是由React引发的事件处理(比如通过onClick引发的事件处理),调用setState不会同步更新this.state,除此之外的setState调用会同步执行this.state 。所谓“除此之外”,指的是绕过React通过addEventListener直接添加的事件处理函数,还有通过setTimeout/setInterval产生的异步调用。
  原因: 在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。
  注意: setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。

  class Example extends React.Component {
    constructor() {
      super();
      this.state = {
        val: 0
      };
    }
    
    componentDidMount() {
      this.setState({val: this.state.val + 1});
      console.log(this.state.val);    // 第 1 次 log

      this.setState({val: this.state.val + 1});
      console.log(this.state.val);    // 第 2 次 log

      setTimeout(() => {
        this.setState({val: this.state.val + 1});
        console.log(this.state.val);  // 第 3 次 log

        this.setState({val: this.state.val + 1});
        console.log(this.state.val);  // 第 4 次 log
      }, 0);
    }

    render() {
      return null;
    }
  };

  输出结果为:0 0 2 3

3、React hooks的优点

  •   最大的优点是更容易复用代码:通过自定义 hooks 来复用状态,从而解决了类组件有些时候难以复用逻辑的问题
  •   组件树层级变浅,
  •   代码更加简洁,代码的可读性更好
不需要老是去纠结this指向的问题
  •   组件更容易拆分
  •   性能比Class更佳

4、useEffect和useLayoutEffect的区别

  •   useEffect 是异步执行的,而useLayoutEffect是同步执行的。
  •   useEffect 的执行时机是浏览器完成渲染之后,而 useLayoutEffect 的执行时机是浏览器把内容真正渲染到界面之前,和 componentDidMount 等价。
  •   ssr也正是因为 useLayoutEffect 可能会导致渲染结果不一样的关系,如果你在 ssr 的时候使用这个函数会有一个 warning。改写方法如下:

import { useEffect, useLayoutEffect } from 'react';
export const useCustomLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;

5、介绍下useState、useReducer

useReducer和useState都可以用来管理组件的状态,useReducer将状态和状态的变化统一管理在reducer函数里面,这样对于一些复杂的状态管理会十分方便我们debug,因为它对状态的改变是封闭的。而由于useState返回的setState可以直接在任意地方设置我们状态的值,当我们组件的状态转换逻辑十分复杂时,它将很难debug,因为它是开放的状态管理。

  useState情况使用

  •   state的值是JS原始数据类型,如number, string和boolean等
  •   state的转换逻辑十分简单
  •   组件内不同的状态是没有关联的,它们可以使用多个独立的useState来单独管理
 


  useReducer情况使用

  •   state的值是object或者array
  •   state的转换逻辑十分复杂, 需要使用reducer函数来统一管理
  •   组件内多个state互相关联,改变一个状态时也需要改变另一个,放在同一个state内使用reducer来统一管理
  •   状态定义在父级组件,不过需要在深层次嵌套的子组件中使用和改变父组件的状态,可以同时使用useReducer和useContext两个hook,将dispatch方法放进context里面来避免组件的props drilling
  •   如果你希望你的状态管理是可预测的和可维护的,请useReducer
  •   如果你希望你的状态变化可以被测试,请使用useReducer


6、介绍下useCallback、useMemo、memo

  三者都是避免重复渲染,从而达到性能优化的目的
  Memo:
  如果你的组件在相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在React.memo中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。
  memo是一个高阶组件。它的功能我们可以这么理解:
  被调用时返回传入的组件
  每次传入的组件要执行更新时,组件的新props和之前的老props会进行一次浅比较:
  结果相等,不触发更新
  结果不相等,触发更新,重新渲染

  useCallBack和useMemo唯一的区别是:useMemo返回的是传入的回调函数的执行结果,useCallBack返回的是传入的回调函数。本质上就是useMemo的语法糖。

  注意:不要滥用useMemo、useCallBack
  使用useMemo、useCallBack时,本身会产生额外的开销,并且这两个方法必须和memo搭配使用,否则很可能会变成负优化。
  因此,在实际项目中,需要结合实际场景,评估重复渲染和创建useCallBack/useCallBack的开销来判断到底用不用useCallBack、useMemo。


  总结

  •   memo与class组件中的pureComponent类似,通过props浅比较来判断组件需不需要重新渲染
  •   useMemo、useCallBack通过浅比较依赖数组项中的变量,判断对应变量/function需不需要重新生成
  •   useMemo、useCallBack不要滥用,需要结合具体场景

7、React性能优化:如何实现父组件更新时,子组件不更新

  老版本:子组件中在shouldComponentUpdate判断是否更新
  新版本: 使用memo

8、react组件之间的通信方式

    * 父组件 => 子组件:

        1. Props

        2. ref

    * 子组件 => 父组件:

        3. 回调函数

        4. 通过事件冒泡机制

    * 兄弟组件之间:

        5. 利用父组件通信

    * 不相关的组件之间:

        6. Context

        7. Portals:适用的场景 Tooltip、Modal、Popup、Dropdown等

        8. 全局变量

        9. 观察者模式:可以通过给document添加自定义事件实现

        10. redux/mobx/zustand/jotai/recoil/valtio等


详细介绍:10种React组件之间通信的方法_react组件通信的方法_jialiang808的博客-CSDN博客

9、react全局状态管理有哪些方式

  context/redux/mobx/zustand/jotai/recoil/valtio
【前端状态管理】React 状态管理工具如何选 context/redux/mobx/zustand/jotai/recoil/valtio_AwesomeDevin的博客-CSDN博客

10、react高阶组件:应用场景、ref、静态方法

  高阶函数:如果一个函数 接受一个或多个函数作为参数或者返回一个函数 就可称之为 高阶函数 。
  高阶组件:如果一个函数 接受一个或多个组件作为参数并且返回一个组件 就可称之为 高阶组件。

  React 中的高阶组件主要有两种形式:属性代理 和 反向继承。

  属性代理类型的高阶组件中可以做什么呢?

  •   操作 props
  •   抽离 state
  •   通过 ref 访问到组件实例
  •   用其他元素包裹传入的组件 WrappedComponent


11、受控组件(Controlled Component)与不受控组件(Uncontrolled Component)的区别

  •   受控组件通过change事件(在用户输入每个字符时触发)和value属性实现。
  •   受控组件通过value属性控制输入元素的值,通过change事件处理函数处理所有的用户输入。
如果value设置为一个固定的值,而未设置其change事件处理函数来设置state,输入元素是不可编辑的。value属性在设置为null或者undefined时,输入元素仍旧是可编辑的。
  •   受控组件需要编写每个输入元素的处理函数,比较繁琐,对于某些输入处理逻辑相同的元素,可通过name属性统一处理。

  •   受控组件表单的值由React控制,不受控组件表单的值由DOM控制,其单一数据源保存在DOM中。
  •   不受控组件不需要对每个输入元素编写change事件处理函数来更新状态。在需要获取输入元素的值时可使用ref。

12、React为什么不建议在 for 循环中使用 useEffect

  1. function MyComponent() {
  2. for (let i = 0; i < 5; i++) {
  3. const [count, setCount] = useState(0);
  4. useEffect(() => {
  5. console.log(`Count is: ${count}`);
  6. }, []);
  7. }
  8. return <div>My Component</div>;
  9. }

在上述代码中,循环中的每次迭代都会创建一个新的状态 count 和对应的 setState 函数 setCount,以及一个 useEffect。由于每次循环都会创建新的状态和副作用,而 useEffect 中依赖项为空数组,只会执行一次,因此 console.log 只会输出 "Count is: 0",而不会根据不同的循环迭代更新 count 的值。

13、Redux原理及工作流程

https://blog.csdn.net/weixin_46116626/article/details/124693939​​​​​​11

14、React 性能优化介绍

React 性能优化 - 父组件更新时,子组件不进行不必要的更新_jialiang808的博客-CSDN博客

15、React 框架源码的理解

https://blog.csdn.net/jialiang808/article/details/131776326

16、介绍一下useRef

在 React 中,useRef 是一个 Hook,用于在函数组件中创建和访问持久化的引用。useRef 提供了一种方式来在函数组件中存储和访问不会触发重新渲染的数据。与 useState 不同,useRef 创建的引用对象的值可以在多次渲染之间保持不变,并且在更新其值时不会引起组件重新渲染。

useRef 的主要用途有以下几个方面:

  1. 访问 DOM 元素:通过 useRef 创建一个引用对象,并将其赋值给 JSX 元素的 ref 属性,从而可以在函数组件中访问到对应的 DOM 节点。

  2. 缓存变量:由于函数组件在每次渲染时都会重新执行,可以使用 useRef 来缓存变量,确保变量在多次渲染之间保持不变,类似于类组件中的实例变量。

  3. 存储其他值:useRef 可以用于存储其他不需要触发组件重新渲染的值。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/857529
推荐阅读
相关标签
  

闽ICP备14008679号