Redux:为什么我的 useEffect() 会在每个页面重新渲染时不断重新渲染它的值
Redux: Why does my useEffect() keeps rerendering its value on every page rerender
我在学习react-redux
。
我遇到了以下问题:
- 我进行了两次异步 api 调用(使用
redux-thunk
):
- 第一个获取国家名称(在一个对象中,例如:
{countries: [{...}, ...]}
。
- 我之后使用的那些国家/地区名称进行第二次 api 调用,以获取这些国家/地区的所有足球联赛(有时,有 none,所以我得到一个
null
).在这种情况下,将分别使用每个 countryName 进行调用。我从结果中得出一个数组。
- 这个数组长度为 255 米,我从中过滤掉
null
值并映射联赛名称。
- 点击联赛名称后,会呈现一个页面 (
{Link} from "react-router-dom";
)。
现在我的问题出现了
- 当我单击以返回我的主页 (
<Link to={"/"} >
) 时,两个 useEffect()
正在再次进行 api 呼叫。为什么?
这是我的 useEffect()
:
的代码
const dispatch = useDispatch();
const selectAllCountries = useSelector(state => state.allCountries);
const selectAllLeagues = useSelector(state => state.allLeagues);
useEffect(() => {
dispatch(allCountries());
}, [dispatch]);
useEffect(() => {
if(!_.isEmpty(selectAllCountries.data)) {
selectAllCountries.data.countries.map(el => dispatch(allLeagues(el.name_en)));
}
}, [dispatch, selectAllCountries.data]);
我尝试制作一个自定义挂钩并将 useEffect()
放在那里:
const useCountries = getCountries => {useEffect(() => {
dispatch(getCountries());
},[getCountries])}
useCountries(allCountries);
按照此处的建议:
但这并没有帮助。
如有任何帮助,我们将不胜感激。
答案:
在“./actions/.../allLeagues.js
...
import _ from "lodash";
export const allLeagues = (country) => async (dispatch, getState) => {
if (!_.isEmpty(getState().allLeagues) && !_.isEmpty(getState().allLeagues.data)) {
return Promise.resolve();
} else {
try {
...
}
}
}
问题,这也很有帮助:
Fetching data from store if exists or call API otherwise in React
(看看关于 getStore()
的回答)
如上面的评论所述,当您单击转到新页面时,主页会卸载。当您返回时,页面 re-mounts 和效果再次运行,触发另一个 API 调用。您可以通过检查这些值是否已存在于您的商店中来阻止 API 调用。我个人喜欢在 action creator 中这样做,但您也可以在 effect 中这样做。
检查动作创建器中的状态:
function allLeagues(countryName) {
return (dispatch, getState) => {
// Call `getState` and check whether `allLeagues` has been populated yet.
const { allLeagues } = getState();
if (allLeagues && allLeagues.data && allLeagues.data.length) {
// You already have the data, no need to make the API call.
return Promise.resolve();
}
// No data, make the API call...
};
}
正在检查效果中的状态:
useEffect(() => {
// Check whether the league data is set or not.
if(!_.isEmpty(selectAllCountries.data) && _.isEmpty(selectAllLeagues.data)) {
selectAllCountries.data.countries.map(el => dispatch(allLeagues(el.name_en)));
}
}, [dispatch, selectAllCountries.data, selectAllLeagues.data]);
我在学习react-redux
。
我遇到了以下问题:
- 我进行了两次异步 api 调用(使用
redux-thunk
):
- 第一个获取国家名称(在一个对象中,例如:
{countries: [{...}, ...]}
。
- 我之后使用的那些国家/地区名称进行第二次 api 调用,以获取这些国家/地区的所有足球联赛(有时,有 none,所以我得到一个
null
).在这种情况下,将分别使用每个 countryName 进行调用。我从结果中得出一个数组。 - 这个数组长度为 255 米,我从中过滤掉
null
值并映射联赛名称。 - 点击联赛名称后,会呈现一个页面 (
{Link} from "react-router-dom";
)。 现在我的问题出现了 - 当我单击以返回我的主页 (
<Link to={"/"} >
) 时,两个useEffect()
正在再次进行 api 呼叫。为什么?
这是我的 useEffect()
:
const dispatch = useDispatch();
const selectAllCountries = useSelector(state => state.allCountries);
const selectAllLeagues = useSelector(state => state.allLeagues);
useEffect(() => {
dispatch(allCountries());
}, [dispatch]);
useEffect(() => {
if(!_.isEmpty(selectAllCountries.data)) {
selectAllCountries.data.countries.map(el => dispatch(allLeagues(el.name_en)));
}
}, [dispatch, selectAllCountries.data]);
我尝试制作一个自定义挂钩并将 useEffect()
放在那里:
const useCountries = getCountries => {useEffect(() => {
dispatch(getCountries());
},[getCountries])}
useCountries(allCountries);
按照此处的建议:
但这并没有帮助。
如有任何帮助,我们将不胜感激。
答案:
在“./actions/.../allLeagues.js
...
import _ from "lodash";
export const allLeagues = (country) => async (dispatch, getState) => {
if (!_.isEmpty(getState().allLeagues) && !_.isEmpty(getState().allLeagues.data)) {
return Promise.resolve();
} else {
try {
...
}
}
}
问题,这也很有帮助:
Fetching data from store if exists or call API otherwise in React
(看看关于 getStore()
的回答)
如上面的评论所述,当您单击转到新页面时,主页会卸载。当您返回时,页面 re-mounts 和效果再次运行,触发另一个 API 调用。您可以通过检查这些值是否已存在于您的商店中来阻止 API 调用。我个人喜欢在 action creator 中这样做,但您也可以在 effect 中这样做。
检查动作创建器中的状态:
function allLeagues(countryName) {
return (dispatch, getState) => {
// Call `getState` and check whether `allLeagues` has been populated yet.
const { allLeagues } = getState();
if (allLeagues && allLeagues.data && allLeagues.data.length) {
// You already have the data, no need to make the API call.
return Promise.resolve();
}
// No data, make the API call...
};
}
正在检查效果中的状态:
useEffect(() => {
// Check whether the league data is set or not.
if(!_.isEmpty(selectAllCountries.data) && _.isEmpty(selectAllLeagues.data)) {
selectAllCountries.data.countries.map(el => dispatch(allLeagues(el.name_en)));
}
}, [dispatch, selectAllCountries.data, selectAllLeagues.data]);