gpt4 book ai didi

javascript - 对 React Hooks 的 useFetch 函数进行单个条件调用的正确方法?

转载 作者:行者123 更新时间:2023-11-28 03:31:56 25 4
gpt4 key购买 nike

我构建了一个 useFetch 函数,该函数与此密切相关:https://www.robinwieruch.de/react-hooks-fetch-data这是它的简化版本:How to correctly call useFetch function?

请注意,一旦启动获取,isLoading 就会设置为 true。

我有一个用例,其中只需要为管理员用户发出提取调用。这是我添加到 React 组件中的代码:

const [companies, companiesFetch] = useFetch(null, {});

if (appStore.currentAccessLevel === 99 && !companies.isLoading && newUsers.companies.length === 0) {
console.log('About to call companiesFetch');
companiesFetch(`${API_ROOT()}acct_mgmt/companies`);
}

useEffect(() => {
if (!companies.isLoading && companies.status === 200) {
newUsers.companies = companies.data.companies;
}
}, [companies.isLoading, companies.status, newUsers.companies, companies.data]);

第一个 if 语句的想法是仅在满足以下所有条件时才进行 fetch 调用: 1. 当前登录的用户是admin。 2. 之前未调用过companiesFetch。 3. newUsers.companies 尚未填充。

这似乎合乎逻辑,但如果我运行此代码,companiesFetch 在应用程序崩溃之前会被调用 25 次。我认为问题是时间问题,即 companies.isLoading 设置得不够快。

你会如何解决这个问题?

最佳答案

根据您在链接中提供的简化示例,问题在于调用 fetchData 的 useFetch() 实现中的 useEffect() () 在第一次渲染后无条件执行。根据您的用例,您不需要该行为,因为您是根据您枚举的条件手动调用它。

除此之外,您还通过直接在功能组件中调用 companiesFetch() 加剧了问题,而您不应该这样做,因为 fetchData() > 同步调用 setState() 并在渲染期间修改组件的状态。

您可以通过首先修改 useFetch() 以在第一次渲染后删除无条件提取来解决这些问题,然后将条件逻辑移至 useEffect()组件内的回调。以下是我实现 useFetch() 的方法:

const initialFetchState = { isLoading: false, isError: false };

// automatically merge update objects into state
const useLegacyState = initialState => useReducer(
(state, update) => ({ ...state, ...update }),
initialState
);

export const useFetch = config => {
const instance = useMemo(() => axios.create(config), [config]);
const [state, setState] = useLegacyState(initialFetchState);
const latestRef = useRef();
const fetch = useCallback(async (...args) => {
try {
// keep ref for most recent call to fetch()
const current = latestRef.current = Symbol();

setState({ isError: false, isLoading: true });

const { data } = await instance.get(...args).finally(() => {
// cancel if fetch() was called again before this settled
if (current !== latestRef.current) {
return Promise.reject(new Error('cancelled by later call'));
}
});

setState({ data });
} catch (error) {
if (current === latestRef.current) {
setState({ isError: true });
}
} finally {
if (current === latestRef.current) {
setState({ isLoading: false });
}
}
}, [instance]);

return [state, fetch];
};

以下是我在 useEffect() 中调用它的方法,以防止同步调用 setState():

const [companies, companiesFetch] = useFetch({ baseURL: API_ROOT() });
const [newUsers, setNewUsers] = useState({ companies: [] });

useEffect(() => {
if (!companies.isLoading) {
if (appStore.currentAccessLevel === 99 && newUsers.companies.length === 0) {
console.log('About to call companiesFetch');
companiesFetch('acct_mgmt/companies');
} else if (companies.status === 200 && newUsers.companies !== companies.data.companies) {
setNewUsers({ companies: companies.data.companies });
}
}
}, [appStore.currentAccessLevel, companies, newUsers]);

在您的示例中,我不确定 newUsers 声明的范围,但在 useEffect() 中看到 newUsers.companies = ... 回调引起了一些担忧,因为这意味着您的功能组件是不纯粹的,这很容易导致微妙的错误。

关于javascript - 对 React Hooks 的 useFetch 函数进行单个条件调用的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58100994/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com