在 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 change
和 component mount
,请编写 TWO
useEffect
函数。 data change
和 component 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]);
请记住,我不会那样做,因为如果您没有任何数据,您可能会陷入无限循环,但在其他情况下这是一种很好的技术。
我想实现以下目标。
来自 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 change
和 component mount
,请编写 TWO
useEffect
函数。 data change
和 component 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]);
请记住,我不会那样做,因为如果您没有任何数据,您可能会陷入无限循环,但在其他情况下这是一种很好的技术。