根据文件:

componentDidUpdate()在更新发生后立即调用。初始呈现时不调用此方法。

我们可以使用新的useEffect()钩子来模拟componentDidUpdate(),但似乎每次渲染后都会运行useEffect(),甚至是第一次渲染。我如何让它在初始渲染时不运行?

正如你在下面的例子中看到的,componentDidUpdateFunction在初始渲染期间被打印,但是componentDidUpdateClass在初始渲染期间没有被打印。

function ComponentDidUpdateFunction() { const [count, setCount] = React.useState(0); React.useEffect(() => { console.log("componentDidUpdateFunction"); }); return ( <div> <p>componentDidUpdateFunction: {count} times</p> <button onClick={() => { setCount(count + 1); }} > Click Me </button> </div> ); } class ComponentDidUpdateClass extends React.Component { constructor(props) { super(props); this.state = { count: 0, }; } componentDidUpdate() { console.log("componentDidUpdateClass"); } render() { return ( <div> <p>componentDidUpdateClass: {this.state.count} times</p> <button onClick={() => { this.setState({ count: this.state.count + 1 }); }} > Click Me </button> </div> ); } } ReactDOM.render( <div> <ComponentDidUpdateFunction /> <ComponentDidUpdateClass /> </div>, document.querySelector("#app") ); <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script> <div id="app"></div>


当前回答

我们可以使用useRef钩子来存储我们喜欢的任何可变值,因此我们可以使用它来跟踪useEffect函数是否第一次运行。

如果希望效果与componentDidUpdate运行在同一阶段,可以使用useLayoutEffect代替。

例子

const { useState, useRef, useLayoutEffect } = React; function ComponentDidUpdateFunction() { const [count, setCount] = useState(0); const firstUpdate = useRef(true); useLayoutEffect(() => { if (firstUpdate.current) { firstUpdate.current = false; return; } console.log("componentDidUpdateFunction"); }); return ( <div> <p>componentDidUpdateFunction: {count} times</p> <button onClick={() => { setCount(count + 1); }} > Click Me </button> </div> ); } ReactDOM.render( <ComponentDidUpdateFunction />, document.getElementById("app") ); <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script> <div id="app"></div>

其他回答

我们可以使用useRef钩子来存储我们喜欢的任何可变值,因此我们可以使用它来跟踪useEffect函数是否第一次运行。

如果希望效果与componentDidUpdate运行在同一阶段,可以使用useLayoutEffect代替。

例子

const { useState, useRef, useLayoutEffect } = React; function ComponentDidUpdateFunction() { const [count, setCount] = useState(0); const firstUpdate = useRef(true); useLayoutEffect(() => { if (firstUpdate.current) { firstUpdate.current = false; return; } console.log("componentDidUpdateFunction"); }); return ( <div> <p>componentDidUpdateFunction: {count} times</p> <button onClick={() => { setCount(count + 1); }} > Click Me </button> </div> ); } ReactDOM.render( <ComponentDidUpdateFunction />, document.getElementById("app") ); <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script> <div id="app"></div>


    const [dojob, setDojob] = useState(false);

    yourfunction(){
        setDojob(true);
    }

    useEffect(()=>{
        if(dojob){
            yourfunction();
            setDojob(false);
        }
    },[dojob]);

你可以把它变成自定义钩子,像这样:

import React, { useEffect, useRef } from 'react';

const useDidMountEffect = (func, deps) => {
    const didMount = useRef(false);

    useEffect(() => {
        if (didMount.current) func();
        else didMount.current = true;
    }, deps);
}

export default useDidMountEffect;

使用的例子:

import React, { useState, useEffect } from 'react';

import useDidMountEffect from '../path/to/useDidMountEffect';

const MyComponent = (props) => {    
    const [state, setState] = useState({
        key: false
    });    

    useEffect(() => {
        // you know what is this, don't you?
    }, []);

    useDidMountEffect(() => {
        // react please run me if 'key' changes, but not on initial render
    }, [state.key]);    

    return (
        <div>
             ...
        </div>
    );
}
// ...

简化的实现

import { useRef, useEffect } from 'react';

function MyComp(props) {

  const firstRender = useRef(true);

  useEffect(() => {
    if (firstRender.current) {
      firstRender.current = false;
    } else {
      myProp = 'some val';
    };

  }, [props.myProp])


  return (
    <div>
      ...
    </div>
  )

}

一个简单的方法是创建一个let,在你的组件中并设置为true。

然后说,如果它为真,将其设置为假,然后返回(停止)useEffect函数

像这样:


    import { useEffect} from 'react';
    //your let must be out of component to avoid re-evaluation 
    
    let isFirst = true
    
    function App() {
      useEffect(() => {
          if(isFirst){
            isFirst = false
            return
          }
    
        //your code that don't want to execute at first time
      },[])
      return (
        <div>
            <p>its simple huh...</p>
        </div>
      );
    }

它类似于@Carmine Tambasciabs解决方案,但没有使用状态:) ‍‍‍‍‍‍ ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍