React中类组件与函数组件

2022-11-08  本文已影响0人  CodeMT

类组件

React 16.8+的生命周期分为三个阶段,分别是挂载阶段、更新阶段、卸载阶段。

react16之后有三个生命周期被废除(但并未删除),保留了前缀UNSAVE_的三个函数,目的是为了向下兼容。如果不使用前缀浏览器控制台会收到信息警告
废弃三个
UNSAVE_componentWillMount
UNSAVE_componentWillReceiveProps
UNSAVE_componentWillUpdate
新增两个
getDerivedStateFromProps
getSnapshotBeforeUpdate

延伸问题:为什么要删除这三个函数?

废弃的三个函数都是在render之前,因为fiber的出现,很可能因为高优先级任务的出现而打断现有任务导致它们会被执行多次。

类组件生命周期第一阶段(挂载/初始化阶段):

类组件生命周期第二阶段(更新阶段):

类组件生命周期第三阶段(卸载阶段):

react性能优化方案

shouldComponentUpdate

控制组件自身或者子组件是否需要更新,尤其在子组件非常多的情况下, 需要进行优化。

PureComponent

PureComponent会帮你 比较新props 跟 旧的props, 新的state和老的state(值相等,或者对象含有相同的属性、且属性值相等 ),决定shouldcomponentUpdate 返回true 或者false, 从而决定要不要呼叫 render function。

注意

如果你的 state 或 props 『永远都会变』,那 PureComponent 并不会比较快,因为shallowEqual 也需要花时间。

export default class MyComponent extends Component {
  // ======= 挂载卸载阶段
  constructor(props: any) {
    super(props);
    this.state = {
      name: 'Hello World',
    };
  }

  // 16.8 新增钩子函数
  static getDerivedStateFromProps(props, state) {
    console.log('判断数据是否需要更新', props, state);
    return null;
  }

  // 16.8 已废弃
  componentWillMount() {
    console.log('渲染之前');
  }

  // 16.8 componentWillMount变更,后续可能会废弃
  UNSAFE_componentWillMount() {
    console.log('渲染之前');
  }

  render() {
    console.log('渲染');
    return <div>MyComponent</div>;
  }

  componentDidMount() {
    console.log('渲染完成');
  }

  // ==========更新阶段,也会重新调用getDerivedStateFromProps

  // 16.8 新增钩子函数
  static getDerivedStateFromProps(props, state) {
    console.log('判断数据是否需要更新', props, state);
    return null;
  }

  // 16.8已废弃
  componentWillReceiveProps(nextProps) {
    console.log('接收到来自父组件的数据', nextProps);
  }

  // 16.8 componentWillReceiveProps变更而来
  UNSAFE_componentWillReceiveProps(nextProps) {
    console.log('接收到来自父组件的数据', nextProps);
  }

  // 16.8新增钩子函数
  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('返回组件更新daom', prevProps, prevState);
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log('判断数据是否更新true,false来判断', nextProps, nextState);
    return false;
  }

  // 16.8已废弃
  componentWillUpdate(nextProps, nextState) {
    console.log('组件数据将要更新', nextProps, nextState);
  }

  // 16.8 变更componentWillUpdate
  UNSAFE_componentWillUpdate(nextProps, nextState) {
    console.log('组件数据将要更新', nextProps, nextState);
  }

  componentDidUpdate(prevProps) {
    console.log('组件数据更新完毕', prevProps);
  }

  // ========= 卸载阶段
  componentWillUnmount() {
    console.log('已经销毁');
  }

  // 其他api
  static getDerivedStateFromError(error) {
    // 更新 state 使下一次渲染可以显示降级 UI
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // 捕获错误信息
  }

  // 增加错误信息校验
  render() {
    if (this.state.hasError) {
      // 你可以渲染任何自定义的降级 UI
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

函数组件

在 React 16.8 之前,函数组件的本质是函数,没有 state 的概念的,因此不存在生命周期一说,仅仅是一个 render 函数而已。
但是引入 Hooks 之后就变得不同了,它能让组件在不使用 class 的情况下拥有 state,所以就有了生命周期的概念,所谓的生命周期其实就是 useState useEffect() useLayoutEffect()

即:Hooks 组件(使用了Hooks的函数组件)有生命周期,而函数组件(未使用Hooks的函数组件)是没有生命周期的

下面,是具体的 class 与 Hooks 的生命周期对应关系:

class 组件 Hooks 组件
constructor useState
getDerivedStateFromProps useState 里面 update 函数
shouldComponentUpdate useMemo
render 函数本身
componentDidMount useEffect
componentDidUpdate useEffect
componentWillUnmount useEffect 里面返回的函数
componentDidCatch
getDerivedStateFromError

1、useState(保存组件状态)

和class的state类似,只不过是独立管理组件变量,

2、useMemo(记忆组件)

useCallback 的功能完全可以由 useMemo 所取代,如果你想通过使用 useMemo 返回一个记忆函数也是完全可以
的。
组件Dom节点,进行计算一些,包括要渲染的Dom或者数据,根据依赖参数进行更新,跟Vue中的computed类似,可用来性能优化

3、useEffect(处理副作用)和useLayoutEffect(同步执行副作用)

hooks的组件生命周期其实就是钩子函数useEffect的不同用法,传递参数的不同会导致不同的结果
useEffect和useLayoutEffect区别:简单来说就是调用时机不同, useLayoutEffect 和原来 componentDidMount & componentDidUpdate 一致,在react完成DOM更新后马上同步调用的代码,会阻塞页面渲染。而 useEffect 是会在整个页面渲染完才会调用的(官方建议优先使用 useEffect)

4、useCallBack(记忆函数)

防止因为组件重新渲染,导致方法被重新创建 ,起到缓存作用; 只有第二个参数 变化了,才重新声明一次
一个钩子函数,通过包裹我们的普通函数进行性能优化

5、useRef(保存引用值)

useRef 用来获取DOM元素对象,也可用来保存数据

6、useReducer和useContext(减少组件层级)

useReducer 可以和 useContext 配合使用。

兄弟之间的组件传值可以使用usecontext这个hook来解决,并且可以用useReducer管理包含多个子值的 state 对象。(模拟一个小型redux场景,而无法替代redux)。
useContext可以帮助我们跨越组件层级直接传递变量,实现数据共享。就是对它所包含的组件树提供全局共享数据的一种技术。
useReducer是useState的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。

7、自定义hooks

当我们想在两个函数之间共享逻辑的时候,我们就会把它提取到第三个函数中。
必须以“use”开头吗?必须如此。这个约定非常重要。不遵循的话,由于无法判断某个函数是否包含对其内部 Hook的调用,React 将无法自动检查你的 Hook 是否违反了 Hook 的规则

import React, { useState, useMemo, useEffect, useCallback } from 'react'

export default function MyComponent (props) =>{
  const [name,setName] = useState('name');

  useMemo(() => ()=>{
    console.log('组件dom节点没有渲染之前调用一次');
  }, []);

  const renderDom = useMemo(() => ()=>{
    console.log('组件dom节点没有渲染之前根据依赖参数props调用');
  }, [props])

  useEffect(() => {
    console.log('组件初始化调用一次');
  }, [])

  useEffect(()=>{
    console.log('组件根据依赖参数props更新调用');
  },[props])

  useEffect(()=>{
    return ()=>{
      console.log('组件卸载调用');
    }
  },[]);

  const handleClick = useCallback(() =>{
    console.log('监听事件通过钩子函数包裹,优化性能');
  },[]);

  return (
    console.log('返回dom节点');
  )
};
上一篇下一篇

猜你喜欢

热点阅读