您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么理解React hooks的渲染邏輯”,在日常操作中,相信很多人在怎么理解React hooks的渲染邏輯問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么理解React hooks的渲染邏輯”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
由于項目環境比較復雜,如果是純class組件,那么就是component、pureComponent、shouldComponentUpdate之類的控制一下是否重新渲染,但是hooks似乎更多場景,接下來一一攻破。
場景一 ,父組件使用hooks,子組件使用class Component
父組件
export default function Test() { const [state, setState] = useState({ a: 1, b: 1, c: 1 }); const [value, setValue] = useState(11); return ( <div> <div> state{state.a},{state.b} </div> <Button type="default" onClick={() => { //@ts-ignore setState({ a: 2, b: 1 }); //@ts-ignore setState({ a: 2, b: 2 }); console.log(state, 'state'); }} > 測試 </Button> <hr /> <div>value{value}</div> <Button type="default" onClick={() => { setValue(value + 1); }} > 測試 </Button> <Demo value={state} /> </div> ); }
子組件
export default class App extends React.Component<Props> { render() { const { props } = this; console.log('demo render'); return ( <div> {props.value.a},{props.value.b} </div> ); } }
結果每次點擊圖中的測試按鈕,子組件Demo都會重新render:
總結:父組件(hook)每次更新,都會導出一個新的state和value對象,子組件肯定會更新(如果不做特殊處理)
場景二,父組件使用hooks,子組件使用class PureComponent
父組件代碼跟上面一樣,子組件使用PureComponent:
export default function Test() { const [state, setState] = useState({ a: 1, b: 1, c: 1 }); const [value, setValue] = useState(11); return ( <div> <div> state{state.a},{state.b} </div> <Button type="default" onClick={() => { //@ts-ignore setState({ a: 2, b: 1 }); //@ts-ignore setState({ a: 2, b: 2 }); console.log(state, 'state'); }} > 測試 </Button> <hr /> <div>value{value}</div> <Button type="default" onClick={() => { setValue(value + 1); }} > 測試 </Button> <Demo value={state} /> </div> ); }
子組件使用PureComponent:
export default class App extends React.PureComponent<Props> { render() { const { props } = this; console.log('demo render'); return ( <div> {props.value.a},{props.value.b} </div> ); } }
結果子組件依舊會每次都重新render:
總結:結論同上,確實是依賴的props改變了,因為父組件是hook模式,每次更新都是直接導出新的value和state.
場景三,搞懂hook的setState跟class組件setState有什么不一樣
理論:class的setState,如果你傳入的是對象,那么就會被異步合并,如果傳入的是函數,那么就會立馬執行替換,而hook的setState是直接替換,那么setState在hook中是異步還是同步呢?
實踐:
組件A:
export default function Test() { const [state, setState] = useState({ a: 1, b: 1, c: 1 }); const [value, setValue] = useState(11); return ( <div> <div> state{state.a},{state.b},{state.c} </div> <Button type="default" onClick={() => { //@ts-ignore setState({ a: 2 }); //@ts-ignore setState({ b: 2 }); console.log(state, 'state'); }} > 測試 </Button> <hr /> <div>value{value}</div> <Button type="default" onClick={() => { setValue(value + 1); }} > 測試 </Button> <Demo value={state} /> </div> ); }
我將setState里兩次分別設置了state的值為{a:2},{b:2},那么是合并,那么我最終得到state應該是{a:2,b:2,c:1},如果是替換,那么最后得到的state是{b:2}
結果:
點擊測試按鈕后,state變成了{b:2},整個value被替換成了{b:2}
結論:hook的setState是直接替換,而不是合并
場景四 , 父組件使用class,子組件使用hook
父組件:
export default class App extends React.PureComponent { state = { count: 1, }; onClick = () => { const { count } = this.state; this.setState({ count: count + 1, }); }; render() { const { count } = this.state; console.log('father render'); return ( <div> <Demo count={count} /> <Button onClick={this.onClick}>測試</Button> </div> ); } }
子組件:
interface Props { count: number; } export default function App(props: Props) { console.log(props, 'props'); return <div>{props.count}</div>; }
邏輯:父組件(class組件)調用setState,刷新自身,然后傳遞給hooks子組件,然后自組件重新調用,更新
場景五
但是我此時需要想實現一個class 組件的 PureComponent一樣的效果,需要用到React.memo
修改父組件代碼為:
export default class App extends React.PureComponent { state = { count: 1, value: 1, }; onClick = () => { const { value } = this.state; this.setState({ count: value + 1, }); }; render() { const { count, value } = this.state; console.log('father render'); return ( <div> <Demo count={count} /> {value} <Button onClick={this.onClick}>測試</Button> </div> ); } }
子組件加入memo,代碼修改為:
import React, { useState, memo } from 'react'; interface Props { count: number; } function App(props: Props) { console.log(props, 'props'); return <div>{props.count}</div>; } export default memo(App);
此時邏輯:class組件改變了自身的state,自己刷新自己,由上而下,傳遞了一個沒有變化的props給hooks組件,hooks組件使用了memo包裹自己。
結果:
我們使用了memo實現了PureComponent的效果,淺比較了一次
場景六,hook,setState每次都是相同的值
export default class App extends React.PureComponent { state = { count: 1, value: 1, }; onClick = () => { const { value } = this.state; this.setState({ value: 1, }); }; render() { const { count, value } = this.state; console.log('father render'); return ( <div> <Demo count={count} /> {value} <Button onClick={this.onClick}>測試</Button> </div> ); } }
結果:由于每次設置的值都是一樣的(都是1),hooks不會更新,同class
場景七,父組件和子組件都使用hook
父組件傳入count給子組件
export default function Father() { const [count, setCount] = useState(1); const [value, setValue] = useState(1); console.log('father render') return ( <div> <Demo count={count} /> <div>value{value}</div> <Button onClick={() => { setValue(value + 1); }} > 測試 </Button> </div> ); }
子組件使用count
export default function App(props: Props) { console.log(props, 'props'); return <div>{props.count}</div>; }
結果:每次點擊測試,都會導致子組件重新render
子組件加入memo
function App(props: Props) { console.log(props, 'props'); return <div>{props.count}</div>; } export default memo(App);
結果:
子組件并沒有觸發更新
這里跟第一個案例class的PureComponent不一樣,第一個案例class的PureComponent子組件此時會重新render,是因為父組件hooks確實每次更新都會導出新的value和state。這里是調用了一次,設置的都是相同的state.所以此時不更新
場景八,父組件hook,子組件hook,使用useCallback緩存函數
父組件:
export default function App() { const [count1, setCount1] = useState(0); const [count2, setCount2] = useState(0); const handleClickButton1 = () => { setCount1(count1 + 1); }; const handleClickButton2 = useCallback(() => { setCount2(count2 + 1); }, [count2]); return ( <div> <div> <Button onClickButton={handleClickButton1}>Button1</Button> </div> <div> <Button onClickButton={handleClickButton2}>Button2</Button> </div> </div> ); }
子組件:
import React from 'react'; const Button = (props: any) => { const { onClickButton, children } = props; return ( <> <button onClick={onClickButton}>{children}</button> <span>{Math.random()}</span> </> ); }; export default React.memo(Button);
結果:雖然我們使用了memo.但是點擊demo1,只有demo1后面的數字改變了,demo2沒有改變,點擊demo2,兩個數字都改變了。
那么我們不使用useCallback看看
父組件修改代碼,去掉useCallback
export default function App() { const [count1, setCount1] = useState(0); const [count2, setCount2] = useState(0); const handleClickButton1 = () => { setCount1(count1 + 1); }; const handleClickButton2 = () => { setCount2(count2+ 1); }; return ( <div> <div> <Demo onClickButton={handleClickButton1}>Demo1</Demo> </div> <div> <Demo onClickButton={handleClickButton2}>Demo</Demo> </div> </div> ); }
子組件代碼不變,結果此時每次都會兩個數字都會跟著變。
官方對useCallback的解釋:
就是返回一個函數,只有在依賴項發生變化的時候才會更新(返回一個新的函數)
結論:
我們聲明的 handleClickButton1 是直接定義了一個方法,這也就導致只要是父組件重新渲染(狀態或者props更新)就會導致這里聲明出一個新的方法,新的方法和舊的方法盡管長的一樣,但是依舊是兩個不同的對象,React.memo 對比后發現對象 props 改變,就重新渲染了。
const a =()=>{} const b =()=>{} a===b //false
這個道理大家都懂,不解釋了
場景九,去掉依賴數組中的count2字段
import React, { useState, useCallback } from 'react'; import Demo from './Demo'; export default function App() { const [count2, setCount2] = useState(0); const handleClickButton2 = useCallback(() => { setCount2(count2 + 1); }, []); return ( <Demo count={count2} onClickButton={handleClickButton2} >測試</Demo> ); }
這樣count2的值永遠都是0,那么這個組件就不會重導出setCount2這個方法,handleClickButton2這個函數永遠不會變化,Button只會更新一次,就是Demo組件接受到的props從0到1到的時候.繼續點擊,count2也是0,但是props有一次從0-1的過程導致Demo子組件被更新,不過count2始終是0,這非常關鍵
場景十,使用useMemo,緩存對象,達到useCallback的效果
使用前
export default function App() { const [count, setCount] = useState(0); const [value, setValue] = useState(0); const userInfo = { age: count, name: 'Jace', }; return ( <div> <div> <Demo userInfo={userInfo} /> </div> <div> {value} <Button onClick={() => { setValue(value + 1); }} ></Button> </div> </div> ); }
子組件使用了memo,沒有依賴value,只是依賴了count.
但是結果每次父組件修改了value的值后,雖然子組件沒有依賴value,而且使用了memo包裹,還是每次都重新渲染了
import React from 'react'; const Button = (props: any) => { const { userInfo } = props; console.log('sub render'); return ( <> <span>{userInfo.count}</span> </> ); }; export default React.memo(Button);
使用后useMemo
const [count, setCount] = useState(0); const obj = useMemo(() => { return { name: "Peter", age: count }; }, [count]); return <Demo obj={obj}>
很明顯,第一種方式,如果每次hook組件更新,那么hook就會導出一個新的count,const 就會聲明一個新的obj對象,即使用了memo包裹,也會被認為是一個新的對象。
看看第二種的結果:
父組件更新,沒有再影響到子組件了。
到此,關于“怎么理解React hooks的渲染邏輯”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。