React:哪些方法会触发 react 重新渲染?重新渲染 render 会做些什么?

930 阅读2分钟

在React中,触发组件重新渲染的方法有很多,主要包括状态变化、属性变化以及上下文变化等。每次重新渲染时,React会执行一系列操作来更新DOM。这些操作包括调用组件的render方法(类组件)或重新执行函数组件的函数体,生成新的虚拟DOM,然后与旧的虚拟DOM进行比较并更新实际的DOM。

触发重新渲染的方法

  1. 状态变化(State Change)

    使用useState或类组件中的setState更新状态会触发重新渲染。

    import React, { useState } from 'react';
    
    const MyComponent = () => {
      const [count, setCount] = useState(0);
    
      const increment = () => setCount(count + 1);
    
      return (
        <div>
          <p>{count}</p>
          <button onClick={increment}>Increment</button>
        </div>
      );
    };
    
  2. 属性变化(Props Change)

    父组件重新渲染并传递新的props给子组件时,子组件也会重新渲染。

    const ParentComponent = () => {
      const [count, setCount] = useState(0);
    
      return (
        <div>
          <button onClick={() => setCount(count + 1)}>Increment</button>
          <ChildComponent count={count} />
        </div>
      );
    };
    
    const ChildComponent = ({ count }) => {
      return <p>{count}</p>;
    };
    
  3. 上下文变化(Context Change)

    使用React的Context API,当上下文值发生变化时,订阅该上下文的组件会重新渲染。

    const MyContext = React.createContext();
    
    const ParentComponent = () => {
      const [value, setValue] = useState('Hello');
    
      return (
        <MyContext.Provider value={value}>
          <button onClick={() => setValue('World')}>Change</button>
          <ChildComponent />
        </MyContext.Provider>
      );
    };
    
    const ChildComponent = () => {
      const contextValue = React.useContext(MyContext);
      return <p>{contextValue}</p>;
    };
    
  4. 强制更新(Force Update)

    在类组件中,可以使用this.forceUpdate()方法强制组件重新渲染,但不推荐频繁使用这个方法。

    class MyComponent extends React.Component {
      forceUpdateHandler = () => {
        this.forceUpdate();
      };
    
      render() {
        return (
          <div>
            <p>Force update example</p>
            <button onClick={this.forceUpdateHandler}>Force Update</button>
          </div>
        );
      }
    }
    

重新渲染时render会做些什么

  1. 生成新的虚拟DOM

    组件的render方法(类组件)或函数体(函数组件)被调用,生成新的虚拟DOM。这个虚拟DOM是一个描述UI结构的轻量级JavaScript对象。

    render() {
      return (
        <div>
          <p>{this.state.count}</p>
          <button onClick={() => this.setState({ count: this.state.count + 1 })}>Increment</button>
        </div>
      );
    }
    
  2. 比较新旧虚拟DOM(Diffing)

    React会将新的虚拟DOM与上一次渲染的旧虚拟DOM进行比较,找出变化的部分。这就是React的Diff算法。

  3. 更新实际DOM(Reconciliation)

    React根据Diff算法的结果,生成最小的DOM操作集来更新实际的DOM。只会对有变化的部分进行更新,从而提升性能。

  4. 调用生命周期方法或钩子

    在类组件中,会触发相关的生命周期方法,如componentDidUpdateshouldComponentUpdate等。

    class MyComponent extends React.Component {
      componentDidUpdate(prevProps, prevState) {
        if (prevState.count !== this.state.count) {
          console.log('Component did update');
        }
      }
    
      // render method...
    }
    

    在函数组件中,会执行useEffect等钩子函数。

    const MyComponent = () => {
      const [count, setCount] = useState(0);
    
      useEffect(() => {
        console.log('Component did update');
      }, [count]);
    
      // return JSX...
    };
    

总结

  • 触发重新渲染的方法:包括状态变化(state change)、属性变化(props change)、上下文变化(context change)以及强制更新(force update)。
  • 重新渲染的过程
    1. 生成新的虚拟DOM。
    2. 比较新旧虚拟DOM,找出变化的部分。
    3. 更新实际DOM,应用最小的DOM操作集。
    4. 调用生命周期方法或钩子函数。

通过理解这些机制,可以更好地优化React组件的性能,避免不必要的重新渲染,从而提升应用的响应速度和用户体验。