React使用useEffect解決setState副作用詳解
介紹一下API
本文主要內(nèi)容:描述了setState與fetch之間產(chǎn)生的沖突副作用,并使用useEffect進(jìn)行解決
API,即Application Programming Interface,應(yīng)用程序接口,是很多程序向開(kāi)發(fā)人員提供的易于使用的抽象化的代碼。
比如經(jīng)常會(huì)用到的查詢天氣API,智能識(shí)圖API,如果是直接照著復(fù)雜的代碼編寫(xiě),會(huì)相當(dāng)不友好。而API則只需按照它們提供的規(guī)則即可簡(jiǎn)單、方便、安全地使用。
fetch()方法訪問(wèn)API
我們會(huì)用到一個(gè)很簡(jiǎn)單的資源API,https://swapi.dev/api/people/1,這是一個(gè)會(huì)返回星球大戰(zhàn)里的人物信息的API。
所以我們要做的事:1、讀取API中提供的數(shù)據(jù); 2、將獲得的數(shù)據(jù)寫(xiě)入state。
首先我們來(lái)做第一步,這里介紹一下fetch()
fetch() 必須接受一個(gè)參數(shù)——資源的路徑。無(wú)論請(qǐng)求成功與否,它都返回一個(gè) Promise 對(duì)象,resolve 對(duì)應(yīng)請(qǐng)求的Response。
一旦 Response被返回,就可以使用一些方法來(lái)定義內(nèi)容的形式
所以我們可以使用以下代碼完成資源API的讀取,并且渲染到頁(yè)面上
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í)輕松地獲得了資源接口所提供給我們的數(shù)據(jù)

然而當(dāng)我們加上控制臺(tái)的輸出后,事情就變得不一樣了
setState的副作用
在這個(gè)程序中,我們可以加上一句console.log在控制臺(tái)輸出后天的運(yùn)行情況,如下
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>
)
}
這時(shí)再運(yùn)行就能清楚地看到在控制臺(tái)處顯示了這個(gè)組件在一直不斷地生成,重新地render

我們可以簡(jiǎn)單地分析一下原因,
- 組件每次render都會(huì)觸發(fā)一次fetch,
- 然后fetch獲取的數(shù)據(jù)傳入setState又會(huì)重新使得組件被render一遍,
而這就形成了一個(gè)死循環(huán),致使組件不斷地生成。
使用useEffect解決這個(gè)問(wèn)題
在useEffect()出現(xiàn)之前,react并沒(méi)有setState后停止render的方法,這就使得setState的使用需要非常謹(jǐn)慎,不過(guò)如今提供了useEffet()來(lái)解決這個(gè)問(wèn)題
useEffect接受兩個(gè)參數(shù),其中第二個(gè)參數(shù)是可選的
useEffect(<function>, <dependency array>)
所以讓我們先來(lái)嘗試一下不使用第二個(gè)參數(shù)會(huì)得到什么結(jié)果
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>
)
}
可以看到在上面的代碼里我們已經(jīng)按照語(yǔ)法要求使用了useEffect(),然而結(jié)果卻不如我們所設(shè)想的只打印一條語(yǔ)句,依舊是一個(gè)死循環(huán)

原因在于只使用一個(gè)參數(shù)的useEffect()的效果是在組件被掛載和被更新兩種情況下執(zhí)行參數(shù)的函數(shù),所以并不能解決更新?tīng)顟B(tài)不執(zhí)行的效果
那么就要用到第二個(gè)參數(shù)了,第二個(gè)參數(shù)叫做dependency array,只有在這個(gè)數(shù)組里的元素更新了,才會(huì)觸發(fā)這個(gè)useEffect
所以這里我們可以將第二個(gè)參數(shù)設(shè)置為一個(gè)空數(shù)組,這樣只有在組件剛剛被掛載的時(shí)候才會(huì)執(zhí)行useEffect,很好的解決了我們只需要讀取一遍API的任務(wù)要求
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ù)運(yùn)行
由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>
)
}
我們?cè)诘诙€(gè)參數(shù)處填入了會(huì)隨著我們點(diǎn)擊而變化的count,所以在我們每次點(diǎn)擊使得count增加以后,count state發(fā)生變化,執(zhí)行useEffect第一個(gè)參數(shù)的函數(shù)

可以看到設(shè)置了count state,再在useEffect中設(shè)置count為dependency,這樣每次改變count的值就會(huì)再一次執(zhí)行useEffect中的函數(shù)。
以上就是React使用useEffect解決setState副作用詳解的詳細(xì)內(nèi)容,更多關(guān)于React useEffect解決setState的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React 使用recharts實(shí)現(xiàn)散點(diǎn)地圖的示例代碼
這篇文章主要介紹了React 使用recharts實(shí)現(xiàn)散點(diǎn)地圖的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
JavaScript的React框架中的JSX語(yǔ)法學(xué)習(xí)入門(mén)教程
這篇文章主要介紹了JavaScript的React框架中的JSX語(yǔ)法學(xué)習(xí)入門(mén)教程,React是由Facebook開(kāi)發(fā)并開(kāi)源的高人氣js框架,需要的朋友可以參考下2016-03-03
React Native驗(yàn)證碼倒計(jì)時(shí)工具類分享
這篇文章主要為大家分享了React Native驗(yàn)證碼倒計(jì)時(shí)工具類,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
使用react-beautiful-dnd實(shí)現(xiàn)列表間拖拽踩坑
相比于react-dnd,react-beautiful-dnd更適用于列表之間拖拽的場(chǎng)景,本文主要介紹了使用react-beautiful-dnd實(shí)現(xiàn)列表間拖拽踩坑,感興趣的可以了解一下2021-05-05
jsoneditor二次封裝實(shí)時(shí)預(yù)覽json編輯器組件react版
這篇文章主要為大家介紹了jsoneditor二次封裝實(shí)時(shí)預(yù)覽json編輯器組件react版示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
react PropTypes校驗(yàn)傳遞的值操作示例
這篇文章主要介紹了react PropTypes校驗(yàn)傳遞的值操作,結(jié)合實(shí)例形式分析了react PropTypes針對(duì)傳遞的值進(jìn)行校驗(yàn)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2020-04-04
react-router4 配合webpack require.ensure 實(shí)現(xiàn)異步加載的示例
本篇文章主要介紹了react-router4 配合webpack require.ensure 實(shí)現(xiàn)異步加載的示例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2018-01-01

