[英]How to make an HTTP hook reusable on the same component
我有一個 HTTP 掛鈎,可以像這樣使用:
const { data, error, isLoading, executeFetch } = useHttp<IArticle[]>('news', []);
在同一個組件中,我想觸發另一個 API 調用 POST 數據並更新其中一篇文章:
const handleChange = (article: IArticle, event: React.ChangeEvent<HTMLInputElement>) => {
executeFetch(`updateNews?id=${article.id}`, { method: 'post', data: { isRead: event.target.checked }});
};
return (
<>
<div className={classes.articleListHeader}>
<h1>Article List</h1>
<small className={classes.headerSubtitle}>{data.length} Articles</small>
</div>
<ul>
{data.map(article => <Article key={article.id} article={article} handleChange={handleChange}/>)}
</ul>
</>
)
我的自定義鈎子來獲取數據:
export function useHttp<T>(initUrl: string, initData: T): UseHttp<T> {
const initOptions: AxiosRequestConfig = { url: initUrl };
const [options, setOptions] = useState(initOptions);
const useHttpReducer = createHttpReducer<T>();
const [state, dispatch] = useReducer(useHttpReducer, {
isLoading: false,
error: '',
data: initData
});
useEffect(() => {
let cancelRequest = false;
const fetchData = async (cancelRequest: boolean = false) => {
if (!options.url) return;
dispatch({ type: API_REQUEST});
try {
const responsePromise: AxiosPromise<T> = axios(options);
const response = await responsePromise;
if (cancelRequest) return;
dispatch({ type: API_SUCCESS, payload: response.data });
} catch (e) {
console.log("Got error", e);
dispatch({ type: API_ERROR, payload: e.message });
}
};
fetchData(cancelRequest);
return () => {
cancelRequest = true;
}
}, [options]);
const executeFetch = (url: string, options: AxiosRequestConfig = axiosInitialOptions): void => {
options.url = url;
setOptions(options);
};
return { ...state, executeFetch}
問題是,當我做這樣的事情時, data
會替換為( POST
請求的)新響應,然后我的 UI 崩潰(沒有更多的文章列表..)
當我需要在同一組件中調用另一個 API 同時保持 HTTP 掛鈎的可重用性時,管理此類情況的良好做法是什么?
我只是想在我的 GET 之后在組件中的某處執行一個 POST 請求 - 我如何以可重用的方式完成它並解決我的問題?
您可以重構自定義掛鈎以接收回調 function。 我省略了cancelRequest
的部分,如果您使用的是axios
您可以通過CancelToken
取消請求:
export function useHttp<T>(initUrl: string): UseHttp<T> {
const initOptions: AxiosRequestConfig = { url: initUrl };
const [options, setOptions] = useState(initOptions);
const useHttpReducer = createHttpReducer<T>();
const [state, dispatch] = useReducer(useHttpReducer, {
isLoading: false,
error: '',
});
const fetchData = async (options, callback) => {
if (!options.url) return;
dispatch({ type: API_REQUEST});
try {
const responsePromise: AxiosPromise<T> = axios(options);
const response = await responsePromise;
dispatch({ type: API_SUCCESS, payload: response.data });
callback(response.data);
} catch (e) {
console.log("Got error", e);
dispatch({ type: API_ERROR, payload: e.message });
}
};
const executeFetch = (url: string, requestOptions: AxiosRequestConfig = axiosInitialOptions, callback): void => {
options.url = url;
fetchData({...options, ...requestOptions}, callback);
};
return { ...state, executeFetch}
};
用法:
const [articles, setArticles]= useState();
const { error, isLoading, executeFetch } = useHttpRequest();
const handleChange = (article: IArticle, event: React.ChangeEvent<HTMLInputElement>) => {
executeFetch(`updateNews?id=${article.id}`, { method: 'post', data: { isRead: event.target.checked }}, setArticles);
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.