在 useEffect 中使用 get API 调用反应挂钩 useCallback 行为不正确

React hook useCallback with get API call inside useEffect not behaving correctly

我想实现以下目标。

来自 redux 的操作已导入此组件。它从我用作数据库的 firebase 获取数据。数据显示在该组件内。

我的问题是每次安装组件时都会获取数据,这不是一个理想的场景。

我想阻止这种行为。

理想情况是只在第一次渲染组件时获取数据,之后不再获取数据。当然它也应该在数据更改时获取,否则不会。我使用了useCallback,但下面的代码肯定有错误。 Token 和 Id 在用户认证时传递。

import { fetchFavs } from "../../store/actions";
import { useSelector, useDispatch } from "react-redux";


const token = useSelector((state) => state.auth.token);
  const id = useSelector((state) => state.auth.userId);
  const fetchedFavs = useSelector((state) => state.saveFavs.fetchedFavs);

  const dispatch = useDispatch();

const fetchFavsOptimized = useCallback(() => {
    dispatch(fetchFavs(token, id));
    console.log("rendered");
  }, [token, id, dispatch]);

  useEffect(() => {
    if (token) {
      fetchFavsOptimized();
    }
  }, [fetchFavsOptimized, token]);

仅在组件安装时获取一次:(注意[]

React.useEffect(() => {
    fetchFavsOptimized()
}, []) // <- this empty square brackets allow for one execution during mounting

我不确定,但是 useEffect 的连续调用问题可能是 [fetchFavsOptimized, token]。将 fetchFavsOptimized 函数放在 [] 中可能不是最好的方法。

您想在数据发生变化时获取数据,但是什么数据?你是说 token ?或者别的什么?

React.useEffect() 挂钩允许在数据发生变化时获取,并将此可更改数据放置在 useEffect[here_data] 中。示例:

const [A, setA] = React.useState();

React.useEffect(() => {
    // this block of code will be executed when state 'A' is changed
},[A])

使用 useEffect 的最佳做法是将运行中的条件分开。 如果您需要获取某些 data changecomponent mount,请编写 TWO useEffect 函数。 data changecomponent mount.

分开

有两种方法来处理这个问题,一种是显式的,一种是隐式的。

明确的方法是在你的 redux 存储中添加一个新的布尔项,并在每次加载你的组件时检查它,看看你是否应该从数据库加载数据。

所以你的 redux store 可能有一个新的 key/value: dataLoaded: false; 在你的组件中,现在你需要从你的 redux store 加载它并在你的使用效果中检查它:

const dataLoaded = useSelector((state) => state.dataLoaded);

useEffect(() => {
    if (token && !dataLoaded) {
      fetchFavsOptimized();
    }
  }, [fetchFavsOptimized, token, dataLoaded]);

不要忘记在 fetchFavsOptimized 函数中将 dataLoaded 更新为 true从数据库加载数据已完成。 这样做的好处是,每次您想要再次从数据库加载数据库时,只需将 dataLoaded 设置为 false.

隐含的方法是检查数据长度,如果是0则执行加载。假设您以这种形式将数据存储在 redux 存储中:data: [] 并且您的数据是一个数组(您可以通过将数据初始化为 null 来做同样的事情并检查数据是否!== null) 您的组件将如下所示:

const data = useSelector((state) => state.data);

useEffect(() => {
    if (token && data.length === 0) {
      fetchFavsOptimized();
    }
  }, [fetchFavsOptimized, token, data]);

请记住,我不会那样做,因为如果您没有任何数据,您可能会陷入无限循环,但在其他情况下这是一种很好的技术。