国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【譯】如何在React Hooks中獲取數(shù)據(jù)?

habren / 2577人閱讀

摘要:在這種情況下,如果狀態(tài)發(fā)生變化,將再次運行以從獲取數(shù)據(jù)。你可以在內(nèi)做到在表單中獲取數(shù)據(jù)到目前為止,我們只有和按鈕的組合。現(xiàn)在,在獲取數(shù)據(jù)時,可以使用向函數(shù)發(fā)送信息。例如,在成功請求的情況下,用于設(shè)置新狀態(tài)對象的數(shù)據(jù)。

</>復(fù)制代碼

  1. 原文鏈接: https://www.robinwieruch.de/r...

在本教程中,我想通過state和effect hook來像你展示如何用React Hooks來獲取數(shù)據(jù)。我將會使用Hacker News的API來獲取熱門的技術(shù)文章。你將會實現(xiàn)一個屬于你自己的自定義hook來在你程序的任何地方復(fù)用,或者是作為一個npm包發(fā)布出來。

如果你還不知道這個React的新特性,那么點擊React Hooks介紹,如果你想直接查看最后的實現(xiàn)效果,請點擊這個github倉庫。

注意:在未來,React Hooks將不會用于React的數(shù)據(jù)獲取,一個叫做Suspense的特性將會去負責它。但下面的教程仍會讓你去更多的了解關(guān)于React中的state和effect hook。

用React Hooks去獲取數(shù)據(jù)

如果你對在React中獲取數(shù)據(jù)還不熟悉,可以查看我其他的React獲取數(shù)據(jù)的文章。它將會引導你通過使用React的class組件來獲取數(shù)據(jù),并且還可以和render props或者高階組件一起使用,以及結(jié)合錯誤處理和加載狀態(tài)。在這篇文章中,我將會在function組件中使用React Hooks來展示這些功能。

</>復(fù)制代碼

  1. import React, { useState } from "react";
  2. function App() {
  3. const [data, setData] = useState({ hits: [] });
  4. return (
  5. );
  6. }
  7. export default App;

這個App組件展示了一個包含很多項的list(hits = Hacker News 文章)。state和state的更新函數(shù)來自于state hook中useState的調(diào)用,它負責管理我們用來渲染list數(shù)據(jù)的本地狀態(tài),初始狀態(tài)是一個空數(shù)組,此時還沒有為其設(shè)置任何的狀態(tài)。

我們將使用axios來獲取數(shù)據(jù),當然你也可以使用其他的庫或者fetch API,如果你還沒安裝axios,你可以在命令行使用npm install axios來安裝它。然后來實現(xiàn)用于數(shù)據(jù)獲取的effect hook:

</>復(fù)制代碼

  1. import React, { useState, useEffect } from "react";
  2. import axios from "axios";
  3. function App() {
  4. const [data, setData] = useState({ hits: [] });
  5. useEffect(async () => {
  6. const result = await axios(
  7. "http://hn.algolia.com/api/v1/search?query=redux",
  8. );
  9. setData(result.data);
  10. });
  11. return (
  12. );
  13. }
  14. export default App;

通過axios在useEffect中獲取數(shù)據(jù),然后通過setData將數(shù)據(jù)放到組件本地的state中,并通過async/await來處理Promise。

然而當你運行程序的時候,你應(yīng)該會遇到一個討厭的循環(huán)。effect hook不僅在組件mount的時候也會在update的時候運行。因為我們在每一次的數(shù)據(jù)獲取之后,會去通過setState設(shè)置狀態(tài),這時候組件update然后effect就會運行一遍,這就造成了數(shù)據(jù)一次又一次的獲取。我們僅僅是想要在組件mount的時候來獲取一次數(shù)據(jù),這就是為什么我們需要在useEffect的第二個參數(shù)提供一個空數(shù)組,從而實現(xiàn)只在mount的時候觸發(fā)數(shù)據(jù)獲取而不是每一次update。

</>復(fù)制代碼

  1. import React, { useState, useEffect } from "react";
  2. import axios from "axios";
  3. function App() {
  4. const [data, setData] = useState({ hits: [] });
  5. useEffect(async () => {
  6. const result = await axios(
  7. "http://hn.algolia.com/api/v1/search?query=redux",
  8. );
  9. setData(result.data);
  10. }, []);
  11. return (
  12. );
  13. }
  14. export default App;

第二個參數(shù)可以定義hooks所依賴的變量(在一個數(shù)組中去分配),如果一個變量改變了,hooks將會執(zhí)行一次,如果是一個空數(shù)組的話,hooks將不會在組件更新的時候執(zhí)行,因為它沒有監(jiān)聽到任何的變量。

這里還有一個陷阱,在代碼中,我們使用async/await從第三方的API中獲取數(shù)據(jù),根據(jù)文檔,每一個async函數(shù)都將返回一個promise,async函數(shù)聲明定義了一個異步函數(shù),它返回一個asyncFunction對象,異步函數(shù)是通過事件循環(huán)異步操作的函數(shù),使用隱式Promise返回其結(jié)果。但是,effect hook應(yīng)該不返回任何內(nèi)容或清除功能,這就是為什么你會在控制臺看到以下警告:07:41:22.910 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的原因。讓我們通過在effect內(nèi)部使用異步函數(shù)來實現(xiàn)它的解決方案。

</>復(fù)制代碼

  1. import React, { useState, useEffect } from "react";
  2. import axios from "axios";
  3. function App() {
  4. const [data, setData] = useState({ hits: [] });
  5. useEffect(() => {
  6. const fetchData = async () => {
  7. const result = await axios(
  8. "http://hn.algolia.com/api/v1/search?query=redux",
  9. );
  10. setData(result.data);
  11. };
  12. fetchData();
  13. }, []);
  14. return (
  15. );
  16. }
  17. export default App;

簡而言之,這就是用React Hooks獲取數(shù)據(jù)。但是,如果你對錯誤處理、加載提示、如何從表單中觸發(fā)數(shù)據(jù)獲取以及如何實現(xiàn)可重用的數(shù)據(jù)獲取hook感興趣,請繼續(xù)閱讀。

如何通過編程方式/手動方式觸發(fā)hook?

好的,我們在mount后獲取了一次數(shù)據(jù),但是,如果使用input的字段來告訴API哪一個話題是我們感興趣的呢?“Redux”可以作為我們的默認查詢,如果是關(guān)于“React”的呢?讓我們實現(xiàn)一個input元素,使某人能夠獲取“Redux”以外的話題。因此,為input元素引入一個新的狀態(tài)。

</>復(fù)制代碼

  1. import React, { Fragment, useState, useEffect } from "react";
  2. import axios from "axios";
  3. function App() {
  4. const [data, setData] = useState({ hits: [] });
  5. const [query, setQuery] = useState("redux");
  6. useEffect(() => {
  7. const fetchData = async () => {
  8. const result = await axios(
  9. "http://hn.algolia.com/api/v1/search?query=redux",
  10. );
  11. setData(result.data);
  12. };
  13. fetchData();
  14. }, []);
  15. return (
  16. setQuery(event.target.value)}
  17. />
  18. );
  19. }
  20. export default App;

目前,這兩個狀態(tài)彼此獨立,但現(xiàn)在希望將它們耦合起來,以獲取由input中的輸入來查詢指定的項目。通過下面的更改,組件應(yīng)該在掛載之后通過查詢詞獲取所有數(shù)據(jù)。

</>復(fù)制代碼

  1. function App() {
  2. const [data, setData] = useState({ hits: [] });
  3. const [query, setQuery] = useState("redux");
  4. useEffect(() => {
  5. const fetchData = async () => {
  6. const result = await axios(
  7. `http://hn.algolia.com/api/v1/search?query=${query}`,
  8. );
  9. setData(result.data);
  10. };
  11. fetchData();
  12. }, []);
  13. return (
  14. ...
  15. );
  16. }
  17. export default App;

還差一部分:當你嘗試在input中輸入一些內(nèi)容時,在mount之后就不會再獲取任何數(shù)據(jù)了,這是因為我們提供了空數(shù)組作為第二個參數(shù),effect沒有依賴任何變量,因此只會在mount的時候觸發(fā),但是現(xiàn)在的effect應(yīng)該依賴query,每當query改變的時候,就應(yīng)該觸發(fā)數(shù)據(jù)的獲取。

</>復(fù)制代碼

  1. function App() {
  2. const [data, setData] = useState({ hits: [] });
  3. const [query, setQuery] = useState("redux");
  4. useEffect(() => {
  5. const fetchData = async () => {
  6. const result = await axios(
  7. `http://hn.algolia.com/api/v1/search?query=${query}`,
  8. );
  9. setData(result.data);
  10. };
  11. fetchData();
  12. }, [query]);
  13. return (
  14. ...
  15. );
  16. }
  17. export default App;

現(xiàn)在每當input的值更新的時候就可以重新獲取數(shù)據(jù)了。但這又導致了另一個問題:對于input中鍵入的每個字符,都會觸發(fā)該效果,并執(zhí)行一個數(shù)據(jù)提取請求。如何提供一個按鈕來觸發(fā)請求,從而手動hook呢?

</>復(fù)制代碼

  1. function App() {
  2. const [data, setData] = useState({ hits: [] });
  3. const [query, setQuery] = useState("redux");
  4. const [search, setSearch] = useState("");
  5. useEffect(() => {
  6. const fetchData = async () => {
  7. const result = await axios(
  8. `http://hn.algolia.com/api/v1/search?query=${query}`,
  9. );
  10. setData(result.data);
  11. };
  12. fetchData();
  13. }, [query]);
  14. return (
  15. setQuery(event.target.value)}
  16. />
  17. Search
  18. );
  19. }

現(xiàn)在,effect依賴于于search,而不是隨輸入字段中變化的query。一旦用戶點擊按鈕,新的search就會被設(shè)置,并且應(yīng)該手動觸發(fā)effect hook。

</>復(fù)制代碼

  1. function App() {
  2. const [data, setData] = useState({ hits: [] });
  3. const [query, setQuery] = useState("redux");
  4. const [search, setSearch] = useState("redux");
  5. useEffect(() => {
  6. const fetchData = async () => {
  7. const result = await axios(
  8. `http://hn.algolia.com/api/v1/search?query=${search}`,
  9. );
  10. setData(result.data);
  11. };
  12. fetchData();
  13. }, [search]);
  14. return (
  15. ...
  16. );
  17. }
  18. export default App;

此外,search的初始值也設(shè)置為與query相同,因為組件也在mount時獲取數(shù)據(jù),因此結(jié)果應(yīng)反映輸入字段中的值。但是,具有類似的query和search狀態(tài)有點令人困惑。為什么不將實際的URL設(shè)置為狀態(tài)而來代替search?

</>復(fù)制代碼

  1. function App() {
  2. const [data, setData] = useState({ hits: [] });
  3. const [query, setQuery] = useState("redux");
  4. const [url, setUrl] = useState(
  5. "http://hn.algolia.com/api/v1/search?query=redux",
  6. );
  7. useEffect(() => {
  8. const fetchData = async () => {
  9. const result = await axios(url);
  10. setData(result.data);
  11. };
  12. fetchData();
  13. }, [url]);
  14. return (
  15. setQuery(event.target.value)}
  16. />
  17. setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`)
  18. }
  19. >
  20. Search
  21. );
  22. }

這就是使用effect hook獲取隱式編程數(shù)據(jù)的情況。你可以決定effect依賴于哪個狀態(tài)。一旦在點擊或其他effect中設(shè)置此狀態(tài),此effect將再次運行。在這種情況下,如果URL狀態(tài)發(fā)生變化,effect將再次運行以從API獲取數(shù)據(jù)。

React Hooks和loading

讓我們?yōu)閿?shù)據(jù)獲取引入一個加載提示。它只是另一個由state hook管理的狀態(tài)。loading被用于在組件中渲染一個loading提示。

</>復(fù)制代碼

  1. import React, { Fragment, useState, useEffect } from "react";
  2. import axios from "axios";
  3. function App() {
  4. const [data, setData] = useState({ hits: [] });
  5. const [query, setQuery] = useState("redux");
  6. const [url, setUrl] = useState(
  7. "http://hn.algolia.com/api/v1/search?query=redux",
  8. );
  9. const [isLoading, setIsLoading] = useState(false);
  10. useEffect(() => {
  11. const fetchData = async () => {
  12. setIsLoading(true);
  13. const result = await axios(url);
  14. setData(result.data);
  15. setIsLoading(false);
  16. };
  17. fetchData();
  18. }, [url]);
  19. return (
  20. setQuery(event.target.value)}
  21. />
  22. setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`)
  23. }
  24. >
  25. Search
  26. {isLoading ? (
  27. Loading ...
  28. ) : (
  29. )}
  30. );
  31. }
  32. export default App;

一旦調(diào)用該effect進行數(shù)據(jù)獲取(當組件mount或URL狀態(tài)更改時發(fā)生),加載狀態(tài)將設(shè)置為true。一旦請求完成,加載狀態(tài)將再次設(shè)置為false。

React Hooks和錯誤處理

如果在React Hooks中加上錯誤處理呢,錯誤只是用state hook初始化的另一個狀態(tài)。一旦出現(xiàn)錯誤狀態(tài),應(yīng)用程序組件就可以為用戶提供反饋。使用async/await時,通常使用try/catch塊進行錯誤處理。你可以在effect內(nèi)做到:

</>復(fù)制代碼

  1. import React, { Fragment, useState, useEffect } from "react";
  2. import axios from "axios";
  3. function App() {
  4. const [data, setData] = useState({ hits: [] });
  5. const [query, setQuery] = useState("redux");
  6. const [url, setUrl] = useState(
  7. "http://hn.algolia.com/api/v1/search?query=redux",
  8. );
  9. const [isLoading, setIsLoading] = useState(false);
  10. const [isError, setIsError] = useState(false);
  11. useEffect(() => {
  12. const fetchData = async () => {
  13. setIsError(false);
  14. setIsLoading(true);
  15. try {
  16. const result = await axios(url);
  17. setData(result.data);
  18. } catch (error) {
  19. setIsError(true);
  20. }
  21. setIsLoading(false);
  22. };
  23. fetchData();
  24. }, [url]);
  25. return (
  26. setQuery(event.target.value)}
  27. />
  28. setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`)
  29. }
  30. >
  31. Search
  32. {isError &&
    Something went wrong ...
    }
  33. {isLoading ? (
  34. Loading ...
  35. ) : (
  36. )}
  37. );
  38. }
  39. export default App;
React在表單中獲取數(shù)據(jù)

到目前為止,我們只有input和按鈕的組合。一旦引入更多的輸入元素,您可能需要用一個表單元素包裝它們。此外,表單還可以通過鍵盤上的“enter”來觸發(fā)。

</>復(fù)制代碼

  1. function App() {
  2. ...
  3. return (
  4. setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`)
  5. }
  6. >
  7. setQuery(event.target.value)}
  8. />
  9. {isError &&
    Something went wrong ...
    }
  10. ...
  11. );
  12. }

但是現(xiàn)在瀏覽器在單擊提交按鈕時頁面會重新加載,因為這是瀏覽器在提交表單時的固有行為。為了防止默認行為,我們可以通過event.preventDefault()取消默認行為。這也是在React類組件中實現(xiàn)的方法。

</>復(fù)制代碼

  1. function App() {
  2. ...
  3. const doFetch = () => {
  4. setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`);
  5. };
  6. return (
  7. {
  8. doFetch();
  9. event.preventDefault();
  10. }}>
  11. setQuery(event.target.value)}
  12. />
  13. {isError &&
    Something went wrong ...
    }
  14. ...
  15. );
  16. }

現(xiàn)在,當你單擊提交按鈕時,瀏覽器不會再重新加載。它和以前一樣工作,但這次使用的是表單,而不是簡單的input和按鈕組合。你也可以按鍵盤上的“回車”鍵。

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

為了提取用于數(shù)據(jù)獲取的自定義hook,請將屬于數(shù)據(jù)獲取的所有內(nèi)容,移動到一個自己的函數(shù)中。還要確保能夠返回App組件所需要的全部變量。

</>復(fù)制代碼

  1. const useHackerNewsApi = () => {
  2. const [data, setData] = useState({ hits: [] });
  3. const [url, setUrl] = useState(
  4. "http://hn.algolia.com/api/v1/search?query=redux",
  5. );
  6. const [isLoading, setIsLoading] = useState(false);
  7. const [isError, setIsError] = useState(false);
  8. useEffect(() => {
  9. const fetchData = async () => {
  10. setIsError(false);
  11. setIsLoading(true);
  12. try {
  13. const result = await axios(url);
  14. setData(result.data);
  15. } catch (error) {
  16. setIsError(true);
  17. }
  18. setIsLoading(false);
  19. };
  20. fetchData();
  21. }, [url]);
  22. const doFetch = () => {
  23. setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`);
  24. };
  25. return { data, isLoading, isError, doFetch };
  26. }

現(xiàn)在,你可以在App組件中使用新的hook了。

</>復(fù)制代碼

  1. function App() {
  2. const [query, setQuery] = useState("redux");
  3. const { data, isLoading, isError, doFetch } = useHackerNewsApi();
  4. return (
  5. ...
  6. );
  7. }

接下來,從dofetch函數(shù)外部傳遞URL狀態(tài):

</>復(fù)制代碼

  1. const useHackerNewsApi = () => {
  2. ...
  3. useEffect(
  4. ...
  5. );
  6. const doFetch = url => {
  7. setUrl(url);
  8. };
  9. return { data, isLoading, isError, doFetch };
  10. };
  11. function App() {
  12. const [query, setQuery] = useState("redux");
  13. const { data, isLoading, isError, doFetch } = useHackerNewsApi();
  14. return (
  15. {
  16. doFetch(
  17. `http://hn.algolia.com/api/v1/search?query=${query}`,
  18. );
  19. event.preventDefault();
  20. }}
  21. >
  22. setQuery(event.target.value)}
  23. />
  24. ...
  25. );
  26. }

初始狀態(tài)也可以變?yōu)橥ㄓ脿顟B(tài)。把它簡單地傳遞給新的自定義hook:

</>復(fù)制代碼

  1. import React, { Fragment, useState, useEffect } from "react";
  2. import axios from "axios";
  3. const useDataApi = (initialUrl, initialData) => {
  4. const [data, setData] = useState(initialData);
  5. const [url, setUrl] = useState(initialUrl);
  6. const [isLoading, setIsLoading] = useState(false);
  7. const [isError, setIsError] = useState(false);
  8. useEffect(() => {
  9. const fetchData = async () => {
  10. setIsError(false);
  11. setIsLoading(true);
  12. try {
  13. const result = await axios(url);
  14. setData(result.data);
  15. } catch (error) {
  16. setIsError(true);
  17. }
  18. setIsLoading(false);
  19. };
  20. fetchData();
  21. }, [url]);
  22. const doFetch = url => {
  23. setUrl(url);
  24. };
  25. return { data, isLoading, isError, doFetch };
  26. };
  27. function App() {
  28. const [query, setQuery] = useState("redux");
  29. const { data, isLoading, isError, doFetch } = useDataApi(
  30. "http://hn.algolia.com/api/v1/search?query=redux",
  31. { hits: [] },
  32. );
  33. return (
  34. {
  35. doFetch(
  36. `http://hn.algolia.com/api/v1/search?query=${query}`,
  37. );
  38. event.preventDefault();
  39. }}
  40. >
  41. setQuery(event.target.value)}
  42. />
  43. {isError &&
    Something went wrong ...
    }
  44. {isLoading ? (
  45. Loading ...
  46. ) : (
  47. )}
  48. );
  49. }
  50. export default App;

這就是使用自定義hook獲取數(shù)據(jù)的方法。hook本身對API一無所知。它從外部接收所有參數(shù),只管理必要的狀態(tài),如數(shù)據(jù)、加載和錯誤狀態(tài)。它執(zhí)行請求并將數(shù)據(jù)作為自定義數(shù)據(jù)獲取hook返回給組件。

Reducer的數(shù)據(jù)獲取hook

reducer hook返回一個狀態(tài)對象和一個改變狀態(tài)對象的函數(shù)。dispatch函數(shù)接收type和可選的payload。所有這些信息都在實際的reducer函數(shù)中使用,從以前的狀態(tài)、包含可選payload和type的action中提取新的狀態(tài)。讓我們看看這在代碼中是如何工作的:

</>復(fù)制代碼

  1. import React, {
  2. Fragment,
  3. useState,
  4. useEffect,
  5. useReducer,
  6. } from "react";
  7. import axios from "axios";
  8. const dataFetchReducer = (state, action) => {
  9. ...
  10. };
  11. const useDataApi = (initialUrl, initialData) => {
  12. const [url, setUrl] = useState(initialUrl);
  13. const [state, dispatch] = useReducer(dataFetchReducer, {
  14. isLoading: false,
  15. isError: false,
  16. data: initialData,
  17. });
  18. ...
  19. };

Reducer Hook接受reducer函數(shù)和一個初始化的狀態(tài)對象作為參數(shù),在我們的例子中,數(shù)據(jù)、加載和錯誤狀態(tài)的初始狀態(tài)的參數(shù)沒有改變,但是它們被聚合到由一個reducer hook管理的一個狀態(tài)對象,而不是單個state hook。

</>復(fù)制代碼

  1. const dataFetchReducer = (state, action) => {
  2. ...
  3. };
  4. const useDataApi = (initialUrl, initialData) => {
  5. const [url, setUrl] = useState(initialUrl);
  6. const [state, dispatch] = useReducer(dataFetchReducer, {
  7. isLoading: false,
  8. isError: false,
  9. data: initialData,
  10. });
  11. useEffect(() => {
  12. const fetchData = async () => {
  13. dispatch({ type: "FETCH_INIT" });
  14. try {
  15. const result = await axios(url);
  16. dispatch({ type: "FETCH_SUCCESS", payload: result.data });
  17. } catch (error) {
  18. dispatch({ type: "FETCH_FAILURE" });
  19. }
  20. };
  21. fetchData();
  22. }, [url]);
  23. ...
  24. };

現(xiàn)在,在獲取數(shù)據(jù)時,可以使用dispatch向reducer函數(shù)發(fā)送信息。dispatch函數(shù)發(fā)送的對象包括一個必填的type屬性和可選的payload。type告訴Reducer函數(shù)需要應(yīng)用哪個狀態(tài)轉(zhuǎn)換,并且Reducer還可以使用payload來提取新狀態(tài)。畢竟,我們只有三種狀態(tài)轉(zhuǎn)換:初始化獲取過程,通知成功的數(shù)據(jù)獲取結(jié)果,以及通知錯誤的數(shù)據(jù)獲取結(jié)果。

在自定義hook的最后,狀態(tài)像以前一樣返回,但是因為我們有一個狀態(tài)對象,而不再是獨立狀態(tài),所以需要用擴展運算符返回state。這樣,調(diào)用useDataApi自定義hook的用戶仍然可以訪問data、isloading和isError:

</>復(fù)制代碼

  1. const useDataApi = (initialUrl, initialData) => {
  2. const [url, setUrl] = useState(initialUrl);
  3. const [state, dispatch] = useReducer(dataFetchReducer, {
  4. isLoading: false,
  5. isError: false,
  6. data: initialData,
  7. });
  8. ...
  9. const doFetch = url => {
  10. setUrl(url);
  11. };
  12. return { ...state, doFetch };
  13. };

最后,還缺少了reducer函數(shù)的實現(xiàn)。它需要處理三種不同的狀態(tài)轉(zhuǎn)換,即FETCH_INIT、FETCH_SUCCESS和FETCH_FAILURE。每個狀態(tài)轉(zhuǎn)換都需要返回一個新的狀態(tài)對象。讓我們看看如何用switch case語句實現(xiàn)這一點:

</>復(fù)制代碼

  1. const dataFetchReducer = (state, action) => {
  2. switch (action.type) {
  3. case "FETCH_INIT":
  4. return { ...state };
  5. case "FETCH_SUCCESS":
  6. return { ...state };
  7. case "FETCH_FAILURE":
  8. return { ...state };
  9. default:
  10. throw new Error();
  11. }
  12. };

reducer函數(shù)可以通過其參數(shù)訪問當前狀態(tài)和action。到目前為止,switch case語句中的每個狀態(tài)轉(zhuǎn)換只會返回原來的狀態(tài)。...語句用于保持狀態(tài)對象不變(意味著狀態(tài)永遠不會直接改變),現(xiàn)在,讓我們重寫一些當前狀態(tài)返回的屬性,以便在每次狀態(tài)轉(zhuǎn)換時更改狀態(tài):

</>復(fù)制代碼

  1. const dataFetchReducer = (state, action) => {
  2. switch (action.type) {
  3. case "FETCH_INIT":
  4. return {
  5. ...state,
  6. isLoading: true,
  7. isError: false
  8. };
  9. case "FETCH_SUCCESS":
  10. return {
  11. ...state,
  12. isLoading: false,
  13. isError: false,
  14. data: action.payload,
  15. };
  16. case "FETCH_FAILURE":
  17. return {
  18. ...state,
  19. isLoading: false,
  20. isError: true,
  21. };
  22. default:
  23. throw new Error();
  24. }
  25. };

現(xiàn)在,每個狀態(tài)轉(zhuǎn)換(由操作的type決定)都將基于先前的狀態(tài)和可選的payload返回一個新的狀態(tài)。例如,在成功請求的情況下,payload用于設(shè)置新狀態(tài)對象的數(shù)據(jù)。

總之,reducer hook確保狀態(tài)管理的這一部分是用自己的邏輯封裝的。通過提供type和可選payload,你將始終已一個可預(yù)測的狀態(tài)結(jié)束。此外,你將永遠不會進入無效狀態(tài)。例如,以前可能會意外地將isloading和isError狀態(tài)設(shè)置為true。在這個案例的用戶界面中應(yīng)該顯示什么?現(xiàn)在,reducer函數(shù)定義的每個狀態(tài)轉(zhuǎn)換都會導致一個有效的狀態(tài)對象。

在effect hook中禁止數(shù)據(jù)獲取

即使組件已經(jīng)卸載(例如,由于使用react路由器導航而離開),設(shè)置組件狀態(tài)也是react中的一個常見問題。我以前在這里寫過這個問題,它描述了如何防止在各種場景中為unmount的組件設(shè)置狀態(tài)。讓我們看看如何防止在自定義hook中為數(shù)據(jù)獲取設(shè)置狀態(tài):

</>復(fù)制代碼

  1. const useDataApi = (initialUrl, initialData) => {
  2. const [url, setUrl] = useState(initialUrl);
  3. const [state, dispatch] = useReducer(dataFetchReducer, {
  4. isLoading: false,
  5. isError: false,
  6. data: initialData,
  7. });
  8. useEffect(() => {
  9. let didCancel = false;
  10. const fetchData = async () => {
  11. dispatch({ type: "FETCH_INIT" });
  12. try {
  13. const result = await axios(url);
  14. if (!didCancel) {
  15. dispatch({ type: "FETCH_SUCCESS", payload: result.data });
  16. }
  17. } catch (error) {
  18. if (!didCancel) {
  19. dispatch({ type: "FETCH_FAILURE" });
  20. }
  21. }
  22. };
  23. fetchData();
  24. return () => {
  25. didCancel = true;
  26. };
  27. }, [url]);
  28. const doFetch = url => {
  29. setUrl(url);
  30. };
  31. return { ...state, doFetch };
  32. };

每個effect hook都有一個clean功能,在組件卸載時運行。clean函數(shù)是從hook返回的一個函數(shù)。在我們的例子中,我們使用一個名為didCancel的布爾標志,讓我們的數(shù)據(jù)獲取邏輯知道組件的狀態(tài)(已裝載/未裝載)。如果組件已卸載,則標志應(yīng)設(shè)置為“tree”,這將導致在最終異步解決數(shù)據(jù)提取后無法設(shè)置組件狀態(tài)。

注意:事實上,數(shù)據(jù)獲取不會中止——這可以通過axios的Cancellation實現(xiàn)——但是對于未安裝的組件,狀態(tài)轉(zhuǎn)換會不再執(zhí)行。因為在我看來,axios的Cancellation并不是最好的API,所以這個防止設(shè)置狀態(tài)的布爾標志也能起到作用。

你已經(jīng)了解了在React中state和effect hook如何用于獲取數(shù)據(jù)。如果您對使用render props和高階組件在類組件(和函數(shù)組件)中獲取數(shù)據(jù)很感興趣,請從一開始就去我的另一篇文章。否則,我希望本文對您了解react hook以及如何在現(xiàn)實場景中使用它們非常有用。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/109309.html

相關(guān)文章

  • ()React hooks:它不是一種魔法,只是一個數(shù)組——使用圖表揭秘提案規(guī)則

    摘要:它并不是實際在內(nèi)部的工作方式,而且它只是一個提案,在未來都會有可能發(fā)生變化。這意味著,數(shù)據(jù)的存儲是獨立于組件之外的。因此,有一個訣竅就是你需要思考作為一組需要一個匹配一致的指針去管理的數(shù)組染陌譯。 原文地址:https://medium.com/@ryardley/... 譯文:染陌 (Github) 譯文地址:https://github.com/answershuto/Blog 轉(zhuǎn)...

    fjcgreat 評論0 收藏0
  • React V16.9來了 無痛感升級 加入性能檢測 【-真香】

    摘要:更新日志應(yīng)對添加以編程方式收集性能測量。在和在將棄用為常見攻擊面。添加對事件的支持。在從調(diào)用時發(fā)出警告,創(chuàng)建循環(huán)。在和從錯誤的渲染器使用時發(fā)出警告。 2019年8月8日,我們發(fā)布了React 16.9。它包含幾個新功能,錯誤修正和新的棄用警告,以幫助準備未來的主要版本。 showImg(https://segmentfault.com/img/bVbwoB5?w=1728&h=666)...

    zzir 評論0 收藏0
  • React V16.9來了 無痛感升級 加入性能檢測 【-真香】

    摘要:更新日志應(yīng)對添加以編程方式收集性能測量。在和在將棄用為常見攻擊面。添加對事件的支持。在從調(diào)用時發(fā)出警告,創(chuàng)建循環(huán)。在和從錯誤的渲染器使用時發(fā)出警告。 2019年8月8日,我們發(fā)布了React 16.9。它包含幾個新功能,錯誤修正和新的棄用警告,以幫助準備未來的主要版本。 showImg(https://segmentfault.com/img/bVbwoB5?w=1728&h=666)...

    ky0ncheng 評論0 收藏0
  • 】什么是React Hooks

    摘要:原文作者譯者博軒于年月的中引入,作為在函數(shù)組件中使用狀態(tài)和生命周期的一種方法。雖然函數(shù)組件之前被稱為無狀態(tài)組件,但是的出現(xiàn),使得這些函數(shù)組件可以使用狀態(tài)。因此,現(xiàn)在許多人將它們視為功能組件。 原文:What are React Hooks?作者:Robin Wieruch譯者:博軒 showImg(https://segmentfault.com/img/remote/14600000...

    lolomaco 評論0 收藏0
  • 】函數(shù)組件和類組件有什么不同?

    摘要:但是,你可能已經(jīng)注意到,當你試圖通過指定依賴數(shù)組來優(yōu)化時,可能會遇到帶有過時閉包的錯誤。這是否意味著閉包是問題所在我不這么認為。到目前為止,我所看到的所有情況下,過時的閉包問題都是由于錯誤地假設(shè)函數(shù)不更改或總是相同而發(fā)生的。 原文鏈接:https://overreacted.io/how-ar... 在很長一段時間內(nèi),標準答案是class components提供更多的特性(像sta...

    gself 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<