簡體   English   中英

如何使 HTTP 掛鈎可在同一組件上重復使用

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM