Reactjs 使用React钩子处理连续相同的useFetch调用的最佳实践?
下面是我构建的Reactjs 使用React钩子处理连续相同的useFetch调用的最佳实践?,reactjs,asynchronous,react-hooks,use-effect,Reactjs,Asynchronous,React Hooks,Use Effect,下面是我构建的useFetch代码,它在很大程度上基于关于该主题的几篇著名文章: const dataFetchReducer = (state: any, action: any) => { let data, status, url; if (action.payload && action.payload.config) { ({ data, status } = action.payload); ({ url } = action.paylo
useFetch
代码,它在很大程度上基于关于该主题的几篇著名文章:
const dataFetchReducer = (state: any, action: any) => {
let data, status, url;
if (action.payload && action.payload.config) {
({ data, status } = action.payload);
({ url } = action.payload.config);
}
switch (action.type) {
case 'FETCH_INIT':
return {
...state,
isLoading: true,
isError: false
};
case 'FETCH_SUCCESS':
return {
...state,
isLoading: false,
isError: false,
data: data,
status: status,
url: url
};
case 'FETCH_FAILURE':
return {
...state,
isLoading: false,
isError: true,
data: null,
status: status,
url: url
};
default:
throw new Error();
}
}
/**
* GET data from endpoints using AWS Access Token
* @param {string} initialUrl The full path of the endpoint to query
* @param {JSON} initialData Used to initially populate 'data'
*/
export const useFetch = (initialUrl: ?string, initialData: any) => {
const [url, setUrl] = useState<?string>(initialUrl);
const { appStore } = useContext(AppContext);
console.log('useFetch: url = ', url);
const [state, dispatch] = useReducer(dataFetchReducer, {
isLoading: false,
isError: false,
data: initialData,
status: null,
url: url
});
useEffect(() => {
console.log('Starting useEffect in requests.useFetch', Date.now());
let didCancel = false;
const options = appStore.awsConfig;
const fetchData = async () => {
dispatch({ type: 'FETCH_INIT' });
try {
let response = {};
if (url && options) {
response = await axios.get(url, options);
}
if (!didCancel) {
dispatch({ type: 'FETCH_SUCCESS', payload: response });
}
} catch (error) {
// We won't force an error if there's no URL
if (!didCancel && url !== null) {
dispatch({ type: 'FETCH_FAILURE', payload: error.response });
}
}
};
fetchData();
return () => {
didCancel = true;
};
}, [url, appStore.awsConfig]);
return [state, setUrl];
}
在上面的代码中,如果公司名称存在,将显示一个错误。如果该组件尚不存在,则该组件所在的向导将前进。这里的关键是处理响应的所有逻辑都包含在useffect
中
除非用户连续两次输入相同的公司名称,否则这一切都可以正常工作。在这种特殊情况下,useFetch
的companyFetch
实例中的url
依赖项不会更改,因此不会向API端点发送新请求
我可以想出几种方法来解决这个问题,但它们看起来都像黑客。我认为其他人以前一定遇到过这个问题,并且很好奇他们是如何解决这个问题的。对于您的问题,这不是一个具体的答案,更多的是另一种方法:您可以始终提供一个函数来触发自定义钩子的重新蚀刻,而不是依赖
useffect
来捕获所有不同的情况
如果您想这样做,请在useFetch
中使用useCallback
,这样您就不会创建无休止的循环:
const triggerFetch = useCallback(async () => {
console.log('Starting useCallback in requests.useFetch', Date.now());
const options = appStore.awsConfig;
const fetchData = async () => {
dispatch({ type: 'FETCH_INIT' });
try {
let response = {};
if (url && options) {
response = await axios.get(url, options);
}
dispatch({ type: 'FETCH_SUCCESS', payload: response });
} catch (error) {
// We won't force an error if there's no URL
if (url !== null) {
dispatch({ type: 'FETCH_FAILURE', payload: error.response });
}
}
};
fetchData();
}, [url, appStore.awsConfig]);
..在钩子的末端:
return [state, setUrl, triggerFetch];
现在,您可以在消费组件中的任何位置使用triggerRefetch()
以编程方式重新蚀刻数据,而不必检查useffect
中的每个案例
下面是一个完整的示例:
对我来说,这与“如何强制我的浏览器跳过特定资源的缓存”有点关系——我知道,XHR不是缓存的,只是类似的情况。在那里,我们可以通过在URL中提供一些随机的无意义参数来避免缓存。所以你也可以这样做
const [requestIndex, incRequest] = useState(0);
...
const [data, updateURl] = useFetch(`${url}&random=${requestIndex}`);
const onSearchClick = useCallback(() => {
incRequest();
}, []);
我发现Paul Cowan的这篇文章以及随后的评论非常有启发性:如果你向下滚动到9月17日下午3:15时Ciprian发表的评论,你会看到一种与我上面的方法类似的方法,但它是有效的。也就是说,
Karen Grigoryan
的第一条评论是最有趣的。在这篇文章中,他解释说,直接从事件处理程序调用异步函数在React中不是一个好方法。我通过设置一个状态变量来测试这种方法,该变量本身会触发useEffect。这似乎是最好的!
const [requestIndex, incRequest] = useState(0);
...
const [data, updateURl] = useFetch(`${url}&random=${requestIndex}`);
const onSearchClick = useCallback(() => {
incRequest();
}, []);