最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當(dāng)前位置: 首頁 - 科技 - 知識(shí)百科 - 正文

ReactHooks中如何請(qǐng)求數(shù)據(jù)(詳解)

來源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 19:26:57
文檔

ReactHooks中如何請(qǐng)求數(shù)據(jù)(詳解)

ReactHooks中如何請(qǐng)求數(shù)據(jù)(詳解):本篇文章給大家?guī)淼膬?nèi)容是關(guān)于React Hooks中如何請(qǐng)求數(shù)據(jù)(詳解),有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。通過這個(gè)教程,我想告訴你在 React 中如何使用 state 和 effect 這兩種 hooks 去請(qǐng)求數(shù)據(jù)。我們將使用眾所周知的 Hac
推薦度:
導(dǎo)讀ReactHooks中如何請(qǐng)求數(shù)據(jù)(詳解):本篇文章給大家?guī)淼膬?nèi)容是關(guān)于React Hooks中如何請(qǐng)求數(shù)據(jù)(詳解),有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。通過這個(gè)教程,我想告訴你在 React 中如何使用 state 和 effect 這兩種 hooks 去請(qǐng)求數(shù)據(jù)。我們將使用眾所周知的 Hac

然而,effect hook 應(yīng)該是什么也不返回的,或者返回一個(gè) clean up 函數(shù)的。這就是為什么你會(huì)在控制臺(tái)看到一個(gè)錯(cuò)誤信息。

index.js:1452 Warning: useEffect function must return a cleanup function or nothing. 
Promises and useEffect(async () => …) are not supported, but you can call an async function inside an effect.

這意味著我們不能直接在 useEffect 函數(shù)使用async。讓我們來實(shí)現(xiàn)一個(gè)解決方案,能夠在 effect hook 中使用 async 函數(shù)。

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
 const [data, setData] = useState({ hits: [] });

 useEffect(() => {
 const fetchData = async () => {
 const result = await axios(
 'http://hn.algolia.com/api/v1/search?query=redux',
 );

 setData(result.data);
 };

 fetchData();
 }, []);

 return (
 <ul>
 {data.hits.map(item => (
 <li key={item.objectID}>
 <a href={item.url}>{item.title}</a>
 </li>
 ))}
 </ul>
 );
}

export default App;

這就是一個(gè)使用 React Hooks 進(jìn)行數(shù)據(jù)請(qǐng)求的小案例。但是,如果你對(duì)錯(cuò)誤處理、loading 態(tài)、如何觸發(fā)表單數(shù)據(jù)獲取以及如何復(fù)用出具處理 hook 感興趣,那我們接著往下看。

如何手動(dòng)或者自動(dòng)觸發(fā)一個(gè) hook?

現(xiàn)在我們已經(jīng)能夠在組件 mount 之后獲取到數(shù)據(jù),但是,如何使用輸入框動(dòng)態(tài)告訴 API 選擇一個(gè)感興趣的話題呢?可以看到之前的代碼,我們默認(rèn)將 "Redux" 作為查詢參數(shù)('http://hn.algolia.com/api/v1/...'),但是我們?cè)趺床樵冴P(guān)于 React 相關(guān)的話題呢?讓我們實(shí)現(xiàn)一個(gè) input 輸入框,可以獲得除了 “Redux” 之外的其他的話題?,F(xiàn)在,讓我們?yōu)檩斎肟蛞胍粋€(gè)新的 state。

import React, { Fragment, useState, useEffect } from 'react';
import axios from 'axios';

function App() {
 const [data, setData] = useState({ hits: [] });
 const [query, setQuery] = useState('redux');

 useEffect(() => {
 const fetchData = async () => {
 const result = await axios(
 'http://hn.algolia.com/api/v1/search?query=redux',
 );

 setData(result.data);
 };

 fetchData();
 }, []);

 return (
 <Fragment>
 <input
 type="text"
 value={query}
 onChange={event => setQuery(event.target.value)}
 />
 <ul>
 {data.hits.map(item => (
 <li key={item.objectID}>
 <a href={item.url}>{item.title}</a>
 </li>
 ))}
 </ul>
 </Fragment>
 );
}

export default App;

現(xiàn)在,請(qǐng)求數(shù)據(jù)和查詢參數(shù)兩個(gè) state 相互獨(dú)立,但是我們需要像一個(gè)辦法希望他們耦合起來,只獲取輸入框輸入的參數(shù)指定的話題文章。通過以下修改,組件應(yīng)該在 mount 之后按照查詢獲取相應(yīng)文章。

...

function App() {
 const [data, setData] = useState({ hits: [] });
 const [query, setQuery] = useState('redux');

 useEffect(() => {
 const fetchData = async () => {
 const result = await axios(
 `http://hn.algolia.com/api/v1/search?query=${query}`,
 );

 setData(result.data);
 };

 fetchData();
 }, []);

 return (
 ...
 );
}

export default App;

實(shí)際上,我們還缺少部分代碼。你會(huì)發(fā)現(xiàn)當(dāng)你在輸入框輸入內(nèi)容后,并沒有獲取到新的數(shù)據(jù)。這是因?yàn)?useEffect 的第二個(gè)參數(shù)只是一個(gè)空數(shù)組,此時(shí)的 effect 不依賴于任何的變量,所以這只會(huì)在 mount 只會(huì)觸發(fā)一次。但是,現(xiàn)在我們需要依賴查詢條件,一旦查詢發(fā)送改變,數(shù)據(jù)請(qǐng)求就應(yīng)該再次觸發(fā)。

...

function App() {
 const [data, setData] = useState({ hits: [] });
 const [query, setQuery] = useState('redux');

 useEffect(() => {
 const fetchData = async () => {
 const result = await axios(
 `http://hn.algolia.com/api/v1/search?query=${query}`,
 );

 setData(result.data);
 };

 fetchData();
 }, [query]);

 return (
 ...
 );
}

export default App;

好了,現(xiàn)在一旦你改變輸入框內(nèi)容,數(shù)據(jù)就會(huì)重新獲取。但是現(xiàn)在又要另外一個(gè)問題:每次輸入一個(gè)新字符,就會(huì)觸發(fā) effect 進(jìn)行一次新的請(qǐng)求。那么我們提供一個(gè)按鈕來手動(dòng)觸發(fā)數(shù)據(jù)請(qǐng)求呢?

function App() {
 const [data, setData] = useState({ hits: [] });
 const [query, setQuery] = useState('redux');
 const [search, setSearch] = useState('redux');

 useEffect(() => {
 const fetchData = async () => {
 const result = await axios(
 `http://hn.algolia.com/api/v1/search?query=${search}`,
 );

 setData(result.data);
 };

 fetchData();
 }, [search]);

 return (
 <Fragment>
 <input
 type="text"
 value={query}
 onChange={event => setQuery(event.target.value)}
 />
 <button type="button" onClick={() => setSearch(query)}>
 Search
 </button>
 <ul>
 {data.hits.map(item => (
 <li key={item.objectID}>
 <a href={item.url}>{item.title}</a>
 </li>
 ))}
 </ul>
 </Fragment>
 );
}

此外,search state 的初始狀態(tài)也是設(shè)置成了與 query state 相同的狀態(tài),因?yàn)榻M件在 mount 的時(shí)候會(huì)請(qǐng)求一次數(shù)據(jù),此時(shí)的結(jié)果也應(yīng)該是反應(yīng)的是輸入框中的搜索條件。然而, search state 和 query state 具有類似的值,這看起來比較困惑。為什么不將真實(shí)的 URL 設(shè)置到 search state 中呢?

function App() {
 const [data, setData] = useState({ hits: [] });
 const [query, setQuery] = useState('redux');
 const [url, setUrl] = useState(
 'http://hn.algolia.com/api/v1/search?query=redux',
 );

 useEffect(() => {
 const fetchData = async () => {
 const result = await axios(url);

 setData(result.data);
 };

 fetchData();
 }, [url]);

 return (
 <Fragment>
 <input
 type="text"
 value={query}
 onChange={event => setQuery(event.target.value)}
 />
 <button
 type="button"
 onClick={() =>
 setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`)
 }
 >
 Search
 </button>

 <ul>
 {data.hits.map(item => (
 <li key={item.objectID}>
 <a href={item.url}>{item.title}</a>
 </li>
 ))}
 </ul>
 </Fragment>
 );
}

這就是通過 effect hook 獲取數(shù)據(jù)的案例,你可以決定 effect 取決于哪個(gè) state。在這個(gè)案例中,如果 URL 的 state 發(fā)生改變,則再次

運(yùn)行該 effect 通過 API 重新獲取主題文章。

Loading 態(tài) 與 React Hooks

讓我們?cè)跀?shù)據(jù)的加載過程中引入一個(gè) Loading 狀態(tài)。它只是另一個(gè)由 state hook 管理的狀態(tài)。Loading state 用于在 App 組件中呈現(xiàn) Loading 狀態(tài)。

import React, { Fragment, useState, useEffect } from 'react';
import axios from 'axios';

function App() {
 const [data, setData] = useState({ hits: [] });
 const [query, setQuery] = useState('redux');
 const [url, setUrl] = useState(
 'http://hn.algolia.com/api/v1/search?query=redux',
 );
 const [isLoading, setIsLoading] = useState(false);

 useEffect(() => {
 const fetchData = async () => {
 setIsLoading(true);

 const result = await axios(url);

 setData(result.data);
 setIsLoading(false);
 };

 fetchData();
 }, [url]);

 return (
 <Fragment>
 <input
 type="text"
 value={query}
 onChange={event => setQuery(event.target.value)}
 />
 <button
 type="button"
 onClick={() =>
 setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`)
 }
 >
 Search
 </button>

 {isLoading ? (
 <p>Loading ...</p>
 ) : (
 <ul>
 {data.hits.map(item => (
 <li key={item.objectID}>
 <a href={item.url}>{item.title}</a>
 </li>
 ))}
 </ul>
 )}
 </Fragment>
 );
}

export default App;

現(xiàn)在當(dāng)組件處于 mount 狀態(tài)或者 URL state 被修改時(shí),調(diào)用 effect 獲取數(shù)據(jù),Loading 狀態(tài)就會(huì)變成 true。一旦請(qǐng)求完成,Loading 狀態(tài)就會(huì)再次被設(shè)置為 false。

錯(cuò)誤處理與 React Hooks

通過 React Hooks 進(jìn)行數(shù)據(jù)請(qǐng)求時(shí),如何進(jìn)行錯(cuò)誤處理呢? 錯(cuò)誤只是另一個(gè)使用 state hook 初始化的另一種狀態(tài)。一旦出現(xiàn)錯(cuò)誤狀態(tài),App 組件就可以反饋給用戶。當(dāng)使用 async/await 函數(shù)時(shí),通常使用 try/catch 來進(jìn)行錯(cuò)誤捕獲,你可以在 effect 中進(jìn)行下面操作:

...

const [isError, setIsError] = useState(false);

useEffect(() => {
 const fetchData = async () => {
 setIsError(false);
 setIsLoading(true);
 
 try {
 const result = await axios(url);
 setData(result.data);
 } catch (error) {
 setIsError(true);
 }
 
 setIsLoading(false);
 };

 fetchData();
}, [url]);

return (
 <Fragment>
 ...
 {isError && <p>Something went wrong ...</p>}
 ...
 <Fragment>
);

effect 每次運(yùn)行都會(huì)重置 error state 的狀態(tài),這很有用,因?yàn)槊看握?qǐng)求失敗后,用戶可能重新嘗試,這樣就能夠重置錯(cuò)誤。為了觀察代

碼是否生效,你可以填寫一個(gè)無用的 URL ,然后檢查錯(cuò)誤信息是否會(huì)出現(xiàn)。

使用表單進(jìn)行數(shù)據(jù)獲取

什么才是獲取數(shù)據(jù)的正確形式呢?現(xiàn)在我們只有輸入框和按鈕進(jìn)行組合,一旦引入更多的 input 元素,你可能想要使用表單來進(jìn)行包裝。此外表單還能夠觸發(fā)鍵盤的 “Enter” 事件。

function App() {
 ...
 const doFetch = (evt) => {
 evt.preventDefault();
 setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`);
 }
 return (
 <Fragment>
 <form
 onSubmit={ doFetch }
 >
 <input
 type="text"
 value={query}
 onChange={event => setQuery(event.target.value)}
 />
 <button type="submit">Search</button>
 </form>

 {isError && <p>Something went wrong ...</p>}

 ...
 </Fragment>
 );
}

自定義 hook 獲取數(shù)據(jù)

我們可以定義一個(gè)自定義的 hook,提取出所有與數(shù)據(jù)請(qǐng)求相關(guān)的東西,除了輸入框的 query state,除此之外還有 Loading 狀態(tài)、錯(cuò)誤處理。還要確保返回組件中需要用到的變量。

const useHackerNewsApi = () => {
 const [data, setData] = useState({ hits: [] });
 const [url, setUrl] = useState(
 'http://hn.algolia.com/api/v1/search?query=redux',
 );
 const [isLoading, setIsLoading] = useState(false);
 const [isError, setIsError] = useState(false);

 useEffect(() => {
 const fetchData = async () => {
 setIsError(false);
 setIsLoading(true);

 try {
 const result = await axios(url);

 setData(result.data);
 } catch (error) {
 setIsError(true);
 }

 setIsLoading(false);
 };

 fetchData();
 }, [url]);

 const doFetch = () => {
 setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`);
 };

 return { data, isLoading, isError, doFetch };
}

現(xiàn)在,我們?cè)?App 組件中使用我們的新 hook 。

function App() {
 const [query, setQuery] = useState('redux');
 const { data, isLoading, isError, doFetch } = useHackerNewsApi();

 return (
 <Fragment>
 ...
 </Fragment>
 );
}

接下來,在外部傳遞 URL 給 DoFetch 方法。

const useHackerNewsApi = () => {
 ...

 useEffect(
 ...
 );

 const doFetch = url => {
 setUrl(url);
 };

 return { data, isLoading, isError, doFetch };
};

function App() {
 const [query, setQuery] = useState('redux');
 const { data, isLoading, isError, doFetch } = useHackerNewsApi();

 return (
 <Fragment>
 <form
 onSubmit={event => {
 doFetch(
 `http://hn.algolia.com/api/v1/search?query=${query}`,
 );

 event.preventDefault();
 }}
 >
 <input
 type="text"
 value={query}
 onChange={event => setQuery(event.target.value)}
 />
 <button type="submit">Search</button>
 </form>

 ...
 </Fragment>
 );
}

初始的 state 也是通用的,可以通過參數(shù)簡單的傳遞到自定義的 hook 中:

import React, { Fragment, useState, useEffect } from 'react';
import axios from 'axios';

const useDataApi = (initialUrl, initialData) => {
 const [data, setData] = useState(initialData);
 const [url, setUrl] = useState(initialUrl);
 const [isLoading, setIsLoading] = useState(false);
 const [isError, setIsError] = useState(false);

 useEffect(() => {
 const fetchData = async () => {
 setIsError(false);
 setIsLoading(true);

 try {
 const result = await axios(url);

 setData(result.data);
 } catch (error) {
 setIsError(true);
 }

 setIsLoading(false);
 };

 fetchData();
 }, [url]);

 const doFetch = url => {
 setUrl(url);
 };

 return { data, isLoading, isError, doFetch };
};

function App() {
 const [query, setQuery] = useState('redux');
 const { data, isLoading, isError, doFetch } = useDataApi(
 'http://hn.algolia.com/api/v1/search?query=redux',
 { hits: [] },
 );

 return (
 <Fragment>
 <form
 onSubmit={event => {
 doFetch(
 `http://hn.algolia.com/api/v1/search?query=${query}`,
 );

 event.preventDefault();
 }}
 >
 <input
 type="text"
 value={query}
 onChange={event => setQuery(event.target.value)}
 />
 <button type="submit">Search</button>
 </form>

 {isError && <p>Something went wrong ...</p>}

 {isLoading ? (
 <p>Loading ...</p>
 ) : (
 <ul>
 {data.hits.map(item => (
 <li key={item.objectID}>
 <a href={item.url}>{item.title}</a>
 </li>
 ))}
 </ul>
 )}
 </Fragment>
 );
}

export default App;

這就是使用自定義 hook 獲取數(shù)據(jù)的方法,hook 本身對(duì)API一無所知,它從外部獲取參數(shù),只管理必要的 state ,如數(shù)據(jù)、 Loading 和

錯(cuò)誤相關(guān)的 state ,并且執(zhí)行請(qǐng)求并將數(shù)據(jù)通過 hook 返回給組件。

用于數(shù)據(jù)獲取的 Reducer Hook

目前為止,我們已經(jīng)使用 state hooks 來管理了我們獲取到的數(shù)據(jù)數(shù)據(jù)、Loading 狀態(tài)、錯(cuò)誤狀態(tài)。然而,所有的狀態(tài)都有屬于自己的 state hook,但是他們又都連接在一起,關(guān)心的是同樣的事情。如你所見,所有的它們都在數(shù)據(jù)獲取函數(shù)中被使用。它們一個(gè)接一個(gè)的被調(diào)用(比如:setIsError、setIsLoading),這才是將它們連接在一起的正確用法。讓我們用一個(gè) Reducer Hook 將這三者連接在一起。

Reducer Hook 返回一個(gè) state 對(duì)象和一個(gè)函數(shù)(用來改變 state 對(duì)象)。這個(gè)函數(shù)被稱為分發(fā)函數(shù)(dispatch function),它分發(fā)一個(gè) action,action 具有 type 和 payload 兩個(gè)屬性。所有的這些信息都在 reducer 函數(shù)中被接收,根據(jù)之前的狀態(tài)提取一個(gè)新的狀態(tài)。讓我們看看在代碼中是如何工作的:

import React, {
 Fragment,
 useState,
 useEffect,
 useReducer,
} from 'react';
import axios from 'axios';

const dataFetchReducer = (state, action) => {
 ...
};

const useDataApi = (initialUrl, initialData) => {
 const [url, setUrl] = useState(initialUrl);

 const [state, dispatch] = useReducer(dataFetchReducer, {
 isLoading: false,
 isError: false,
 data: initialData,
 });

 ...
};

Reducer Hook 以 reducer 函數(shù)和一個(gè)初始狀態(tài)對(duì)象作為參數(shù)。在我們的案例中,加載的數(shù)據(jù)、Loading 狀態(tài)、錯(cuò)誤狀態(tài)都是作為初始狀態(tài)參數(shù),且不會(huì)發(fā)生改變,但是他們被聚合到一個(gè)狀態(tài)對(duì)象中,由 reducer hook 管理,而不是單個(gè) state hooks。

const dataFetchReducer = (state, action) => {
 ...
};

const useDataApi = (initialUrl, initialData) => {
 const [url, setUrl] = useState(initialUrl);

 const [state, dispatch] = useReducer(dataFetchReducer, {
 isLoading: false,
 isError: false,
 data: initialData,
 });

 useEffect(() => {
 const fetchData = async () => {
 dispatch({ type: 'FETCH_INIT' });

 try {
 const result = await axios(url);

 dispatch({ type: 'FETCH_SUCCESS', payload: result.data });
 } catch (error) {
 dispatch({ type: 'FETCH_FAILURE' });
 }
 };

 fetchData();
 }, [url]);

 ...
};

現(xiàn)在,在獲取數(shù)據(jù)時(shí),可以使用 dispatch 函數(shù)向 reducer 函數(shù)發(fā)送信息。使用 dispatch 函數(shù)發(fā)送的對(duì)象具有一個(gè)必填的 type 屬性和一個(gè)可選的 payload 屬性。type 屬性告訴 reducer 函數(shù)需要轉(zhuǎn)換的 state 是哪個(gè),還可以從 payload 中提取新的 state。在這里只有三個(gè)狀態(tài)轉(zhuǎn)換:初始化數(shù)據(jù)過程,通知數(shù)據(jù)請(qǐng)求成功的結(jié)果,以及通知數(shù)據(jù)請(qǐng)求失敗的結(jié)果。

在自定義 hook 的末尾,state 像以前一樣返回,但是因?yàn)槲覀兯械?state 都在一個(gè)對(duì)象中,而不再是獨(dú)立的 state ,所以 state 對(duì)象進(jìn)行解構(gòu)返回。這樣,調(diào)用 useDataApi 自定義 hook 的人仍然可以 data 、isLoading和isError:

const useDataApi = (initialUrl, initialData) => {
 const [url, setUrl] = useState(initialUrl);

 const [state, dispatch] = useReducer(dataFetchReducer, {
 isLoading: false,
 isError: false,
 data: initialData,
 });

 ...

 const doFetch = url => {
 setUrl(url);
 };

 return { ...state, doFetch };
};

最后我們還缺少 reducer 函數(shù)的實(shí)現(xiàn)。它需要處理三個(gè)不同的狀態(tài)轉(zhuǎn)換,分被稱為 FEATCH_INIT、FEATCH_SUCCESS、FEATCH_FAILURE。每個(gè)狀態(tài)轉(zhuǎn)換都需要返回一個(gè)新的狀態(tài)。讓我們看看使用 switch case 如何實(shí)現(xiàn)這個(gè)邏輯:

const dataFetchReducer = (state, action) => {
 switch (action.type) {
 case 'FETCH_INIT':
 return { ...state };
 case 'FETCH_SUCCESS':
 return { ...state };
 case 'FETCH_FAILURE':
 return { ...state };
 default:
 throw new Error();
 }
};

reducer 函數(shù)可以通過其參數(shù)訪問當(dāng)前狀態(tài)和 dispatch 傳入的 action。到目前為止,在 switch case 語句中,每個(gè)狀態(tài)轉(zhuǎn)換只返回前一個(gè)狀態(tài),析構(gòu)語句用于保持 state 對(duì)象不可變(即狀態(tài)永遠(yuǎn)不會(huì)被直接更改)?,F(xiàn)在讓我們重寫一些當(dāng)前 state 返回的屬性,以便在每次轉(zhuǎn)換時(shí)更改 一些 state:

const dataFetchReducer = (state, action) => {
 switch (action.type) {
 case 'FETCH_INIT':
 return {
 ...state,
 isLoading: true,
 isError: false
 };
 case 'FETCH_SUCCESS':
 return {
 ...state,
 isLoading: false,
 isError: false,
 data: action.payload,
 };
 case 'FETCH_FAILURE':
 return {
 ...state,
 isLoading: false,
 isError: true,
 };
 default:
 throw new Error();
 }
};

現(xiàn)在,每個(gè)狀態(tài)轉(zhuǎn)換(action.type決定)都返回一個(gè)基于先前 state 和可選 payload 的新狀態(tài)。例如,在請(qǐng)求成功的情況下,payload 用于設(shè)置新 state 對(duì)象的 data 屬性。

總之,reducer hook 確保使用自己的邏輯封裝狀態(tài)管理的這一部分。通過提供 action type 和可選 payload ,總是會(huì)得到可預(yù)測的狀態(tài)更改。此外,永遠(yuǎn)不會(huì)遇到無效狀態(tài)。例如,以前可能會(huì)意外地將 isLoading 和 isError 設(shè)置為true。在這種情況下,UI中應(yīng)該顯示什么? 現(xiàn)在,由 reducer 函數(shù)定義的每個(gè) state 轉(zhuǎn)換都指向一個(gè)有效的 state 對(duì)象。

在 Effect Hook 中中斷數(shù)據(jù)請(qǐng)求

在React中,即使組件已經(jīng)卸載,組件 state 仍然會(huì)被被賦值,這是一個(gè)常見的問題。我在之前的文章中寫過這個(gè)問題,它描述了如何防止在各種場景中為未掛載組件設(shè)置狀態(tài)。讓我們看看在自定義 hook 中,請(qǐng)求數(shù)據(jù)時(shí)如何防止設(shè)置狀態(tài):

const useDataApi = (initialUrl, initialData) => {
 const [url, setUrl] = useState(initialUrl);

 const [state, dispatch] = useReducer(dataFetchReducer, {
 isLoading: false,
 isError: false,
 data: initialData,
 });

 useEffect(() => {
 let didCancel = false;

 const fetchData = async () => {
 dispatch({ type: 'FETCH_INIT' });

 try {
 const result = await axios(url);

 if (!didCancel) {
 dispatch({ type: 'FETCH_SUCCESS', payload: result.data });
 }
 } catch (error) {
 if (!didCancel) {
 dispatch({ type: 'FETCH_FAILURE' });
 }
 }
 };

 fetchData();

 return () => {
 didCancel = true;
 };
 }, [url]);

 const doFetch = url => {
 setUrl(url);
 };

 return { ...state, doFetch };
};

每個(gè)Effect Hook都帶有一個(gè)clean up函數(shù),它在組件卸載時(shí)運(yùn)行。clean up 函數(shù)是 hook 返回的一個(gè)函數(shù)。在該案例中,我們使用 didCancel 變量來讓 fetchData 知道組件的狀態(tài)(掛載/卸載)。如果組件確實(shí)被卸載了,則應(yīng)該將標(biāo)志設(shè)置為 true,從而防止在最終異步解析數(shù)據(jù)獲取之后設(shè)置組件狀態(tài)。

注意:實(shí)際上并沒有中止數(shù)據(jù)獲取(不過可以通過Axios取消來實(shí)現(xiàn)),但是不再為卸載的組件執(zhí)行狀態(tài)轉(zhuǎn)換。由于 Axios 取消在我看來并不是最好的API,所以這個(gè)防止設(shè)置狀態(tài)的布爾標(biāo)志也可以完成這項(xiàng)工作。

本篇文章到這里就已經(jīng)全部結(jié)束了,更多其他精彩內(nèi)容可以關(guān)注PHP中文網(wǎng)的JavaScript視頻教程欄目!

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

ReactHooks中如何請(qǐng)求數(shù)據(jù)(詳解)

ReactHooks中如何請(qǐng)求數(shù)據(jù)(詳解):本篇文章給大家?guī)淼膬?nèi)容是關(guān)于React Hooks中如何請(qǐng)求數(shù)據(jù)(詳解),有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。通過這個(gè)教程,我想告訴你在 React 中如何使用 state 和 effect 這兩種 hooks 去請(qǐng)求數(shù)據(jù)。我們將使用眾所周知的 Hac
推薦度:
標(biāo)簽: 數(shù)據(jù) 如何 訪問
  • 熱門焦點(diǎn)

最新推薦

猜你喜歡

熱門推薦

專題
Top