useEffect 调用了两次

han*_*ome 7 javascript reactjs react-hooks

我知道为什么会发生这种情况,但想知道避免这种情况的正确方法是什么。\nuseEffect 被调用两次。一个是 data = null,然后是“真实”数据。

\n\n
const [data, setData] = useState(null);\nsomeServiceToFetchData.then(freshData => setData(freshData))\n\nuseEffect(() => {\n    console.log("useEffect called");\n}, [data]);\n
Run Code Online (Sandbox Code Playgroud)\n\n

我应该到处做这样的事情吗?

\n\n
useEffect(() => {\n    if (data) {\n        console.log("useEffect called with real data");\n    }\n}, [data]);\n
Run Code Online (Sandbox Code Playgroud)\n

Sis*_*sir 5

如果你想跳过第一次渲染,你可以使用这样的状态标志。我发现下面的方法不太复杂。

import React, { useState } from 'react';

const Comp = ({dep}) => {
    const [rendered, setRendered] = useState(false);

    useEffect(() => {
        if(rendered){
            // do stuff
        }
        
        if( ! rendered ) {
            setRendered(true);
        }
    }, [dep]);

    // rest of the component code

    return <></>
}
Run Code Online (Sandbox Code Playgroud)


gdh*_*gdh 3

众所周知,useEffect 在初始渲染时被调用一次,并且在依赖数组值的后续更改时也会被调用一次。

在您的情况下,要跳过 useEffect (空情况)的初始执行,请编写一个小的自定义挂钩,这样可以在需要时通用。

成分

import React,  { useState, useEffect } from 'react';
import useEffectSkipInitialRender from "./hook";

const Test = (props) => {
    const [data, setData] = useState(null);

    new Promise((res, rej) => res('my data')).then(freshData => setData(freshData));

    useEffectSkipInitialRender(() => {
        console.log("useEffect called");
    }, [data]);

    return <div>hi</div>
};

export default Test;
Run Code Online (Sandbox Code Playgroud)

定制挂钩

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

const useEffectSkipInitialRender = (callback, dataArr) => {
    const [data, setData] = useState(null);
    const isInitialRender = useRef(true);// in react, when refs are changed component dont re-render 

    useEffect(() => {
        if(isInitialRender.current){// skip initial execution of useEffect
            isInitialRender.current = false;// set it to false so subsequent changes of dependency arr will make useEffect to execute
            return;
        }
        return callback();
    }, dataArr);

};

export default useEffectSkipInitialRender;
Run Code Online (Sandbox Code Playgroud)

如果您希望效果逻辑仅在数据不为空且数据更改时运行,您可以像这样编写自定义挂钩:

import React,  { useEffect } from 'react';

const useEffectOnDataChange = (callback, dataArr) => {
    const someIsNull = dataArr.some(data => data == null);

    useEffect(() => {
        if (someIsNull) return;
        return callback();
    }, dataArr);

}
Run Code Online (Sandbox Code Playgroud)