React使用useEffect解決setState副作用詳解
介紹一下API
本文主要內容:描述了setState與fetch之間產生的沖突副作用,并使用useEffect進行解決
API
,即Application Programming Interface,應用程序接口,是很多程序向開發(fā)人員提供的易于使用的抽象化的代碼。
比如經常會用到的查詢天氣API,智能識圖API,如果是直接照著復雜的代碼編寫,會相當不友好。而API則只需按照它們提供的規(guī)則即可簡單、方便、安全地使用。
fetch()方法訪問API
我們會用到一個很簡單的資源API,https://swapi.dev/api/people/1
,這是一個會返回星球大戰(zhàn)里的人物信息的API。
所以我們要做的事:1、讀取API中提供的數(shù)據(jù); 2、將獲得的數(shù)據(jù)寫入state。
首先我們來做第一步,這里介紹一下fetch()
fetch()
必須接受一個參數(shù)——資源的路徑。無論請求成功與否,它都返回一個 Promise 對象,resolve 對應請求的Response。
一旦 Response被返回,就可以使用一些方法來定義內容的形式
所以我們可以使用以下代碼完成資源API的讀取,并且渲染到頁面上
import React from "react" export default function App() { const [starWarsData, setStarWarsData] = React.useState({}) fetch("https://swapi.dev/api/people/1") .then(res => res.json()) .then(data => setStarWarsData(data)) return ( <div> <pre>{JSON.stringify(starWarsData, null, 2)}</pre> </div> ) }
可以看到我們似乎確實輕松地獲得了資源接口所提供給我們的數(shù)據(jù)
然而當我們加上控制臺的輸出后,事情就變得不一樣了
setState的副作用
在這個程序中,我們可以加上一句console.log
在控制臺輸出后天的運行情況,如下
import React from "react" export default function App() { const [starWarsData, setStarWarsData] = React.useState({}) console.log("component rendered") fetch("https://swapi.dev/api/people/1") .then(res => res.json()) .then(data => setStarWarsData(data)) return ( <div> <pre>{JSON.stringify(starWarsData, null, 2)}</pre> </div> ) }
這時再運行就能清楚地看到在控制臺處顯示了這個組件在一直不斷地生成,重新地render
我們可以簡單地分析一下原因,
- 組件每次render都會觸發(fā)一次fetch,
- 然后fetch獲取的數(shù)據(jù)傳入setState又會重新使得組件被render一遍,
而這就形成了一個死循環(huán),致使組件不斷地生成。
使用useEffect解決這個問題
在useEffect()
出現(xiàn)之前,react并沒有setState后停止render的方法,這就使得setState的使用需要非常謹慎,不過如今提供了useEffet()
來解決這個問題
useEffect接受兩個參數(shù),其中第二個參數(shù)是可選的
useEffect(<function>, <dependency array>)
所以讓我們先來嘗試一下不使用第二個參數(shù)會得到什么結果
import React from "react" export default function App() { const [starWarsData, setStarWarsData] = React.useState({}) console.log("component rendered") React.useEffect(function(){ fetch("https://swapi.dev/api/people/1") .then(res => res.json()) .then(data => setStarWarsData(data)) }) return ( <div> <pre>{JSON.stringify(starWarsData, null, 2)}</pre> </div> ) }
可以看到在上面的代碼里我們已經按照語法要求使用了useEffect()
,然而結果卻不如我們所設想的只打印一條語句,依舊是一個死循環(huán)
原因在于只使用一個參數(shù)的useEffect()
的效果是在組件被掛載
和被更新
兩種情況下執(zhí)行參數(shù)的函數(shù),所以并不能解決更新狀態(tài)不執(zhí)行的效果
那么就要用到第二個參數(shù)了,第二個參數(shù)叫做dependency array
,只有在這個數(shù)組里的元素更新了,才會觸發(fā)這個useEffect
所以這里我們可以將第二個參數(shù)設置為一個空數(shù)組,這樣只有在組件剛剛被掛載的時候才會執(zhí)行useEffect
,很好的解決了我們只需要讀取一遍API的任務要求
import React from "react" export default function App() { const [starWarsData, setStarWarsData] = React.useState({}) console.log("component rendered") React.useEffect(function(){ fetch("https://swapi.dev/api/people/1") .then(res => res.json()) .then(data => setStarWarsData(data)) }, []) return ( <div> <pre>{JSON.stringify(starWarsData, null, 2)}</pre> </div> ) }
使用useEffect操控函數(shù)運行
由dependency array
我們也可以得出另一種用法,可以看以下代碼
import React from "react" export default function App() { const [count, setCount] = React.useState(0) console.log("Component rendered") React.useEffect(() => { console.log("Effect function ran") }, [count]) return ( <div> <h2>The count is {count}</h2> <button onClick={() => setCount(prevCount => prevCount + 1)}>Add</button> </div> ) }
我們在第二個參數(shù)處填入了會隨著我們點擊而變化的count
,所以在我們每次點擊使得count
增加以后,count state
發(fā)生變化,執(zhí)行useEffect
第一個參數(shù)的函數(shù)
可以看到設置了count state
,再在useEffect
中設置count
為dependency
,這樣每次改變count的值就會再一次執(zhí)行useEffect中的函數(shù)。
以上就是React使用useEffect解決setState副作用詳解的詳細內容,更多關于React useEffect解決setState的資料請關注腳本之家其它相關文章!
相關文章
react-native DatePicker日期選擇組件的實現(xiàn)代碼
本篇文章主要介紹了react-native DatePicker日期選擇組件的實現(xiàn)代碼,具有一定的參考價值,有興趣的可以了解下2017-09-09React中路由參數(shù)如何改變頁面不刷新數(shù)據(jù)的情況
這篇文章主要介紹了React中路由參數(shù)如何改變頁面不刷新數(shù)據(jù)的情況,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08