溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么理解React hooks的渲染邏輯

發(fā)布時(shí)間:2021-11-04 15:37:55 來(lái)源:億速云 閱讀:133 作者:iii 欄目:web開發(fā)

這篇文章主要介紹“怎么理解React hooks的渲染邏輯”,在日常操作中,相信很多人在怎么理解React hooks的渲染邏輯問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”怎么理解React hooks的渲染邏輯”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

由于項(xiàng)目環(huán)境比較復(fù)雜,如果是純class組件,那么就是component、pureComponent、shouldComponentUpdate之類的控制一下是否重新渲染,但是hooks似乎更多場(chǎng)景,接下來(lái)一一攻破。

  •  場(chǎng)景一 ,父組件使用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');                  }}              >                  測(cè)試              </Button>              <hr />              <div>value{value}</div>              <Button                  type="default"                  onClick={() => {                      setValue(value + 1);                  }}              >                  測(cè)試              </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>          );      }  }

結(jié)果每次點(diǎn)擊圖中的測(cè)試按鈕,子組件Demo都會(huì)重新render:

怎么理解React hooks的渲染邏輯

總結(jié):父組件(hook)每次更新,都會(huì)導(dǎo)出一個(gè)新的state和value對(duì)象,子組件肯定會(huì)更新(如果不做特殊處理)

  •  場(chǎng)景二,父組件使用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');                  }}              >                  測(cè)試              </Button>              <hr />              <div>value{value}</div>              <Button                  type="default"                  onClick={() => {                      setValue(value + 1);                  }}              >                  測(cè)試              </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>          );      }  }

結(jié)果子組件依舊會(huì)每次都重新render:

怎么理解React hooks的渲染邏輯

總結(jié):結(jié)論同上,確實(shí)是依賴的props改變了,因?yàn)楦附M件是hook模式,每次更新都是直接導(dǎo)出新的value和state.

  •  場(chǎng)景三,搞懂hook的setState跟class組件setState有什么不一樣

理論:class的setState,如果你傳入的是對(duì)象,那么就會(huì)被異步合并,如果傳入的是函數(shù),那么就會(huì)立馬執(zhí)行替換,而hook的setState是直接替換,那么setState在hook中是異步還是同步呢?

實(shí)踐:

組件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');                  }}              >                  測(cè)試              </Button>              <hr />              <div>value{value}</div>              <Button                  type="default"                  onClick={() => {                      setValue(value + 1);                  }}              >                  測(cè)試              </Button>              <Demo value={state} />          </div>      );  }

我將setState里兩次分別設(shè)置了state的值為{a:2},{b:2},那么是合并,那么我最終得到state應(yīng)該是{a:2,b:2,c:1},如果是替換,那么最后得到的state是{b:2}

結(jié)果:

怎么理解React hooks的渲染邏輯

點(diǎn)擊測(cè)試按鈕后,state變成了{(lán)b:2},整個(gè)value被替換成了{(lán)b:2}

結(jié)論:hook的setState是直接替換,而不是合并

  •  場(chǎng)景四 , 父組件使用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}>測(cè)試</Button>              </div>          );      }  }

子組件:

interface Props {      count: number;  }  export default function App(props: Props) {      console.log(props, 'props');      return <div>{props.count}</div>;  }

邏輯:父組件(class組件)調(diào)用setState,刷新自身,然后傳遞給hooks子組件,然后自組件重新調(diào)用,更新

怎么理解React hooks的渲染邏輯

  •  場(chǎng)景五

但是我此時(shí)需要想實(shí)現(xiàn)一個(gè)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}>測(cè)試</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);

此時(shí)邏輯:class組件改變了自身的state,自己刷新自己,由上而下,傳遞了一個(gè)沒(méi)有變化的props給hooks組件,hooks組件使用了memo包裹自己。

結(jié)果:

怎么理解React hooks的渲染邏輯

我們使用了memo實(shí)現(xiàn)了PureComponent的效果,淺比較了一次

  •  場(chǎng)景六,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}>測(cè)試</Button>              </div>          );      }  }

結(jié)果:由于每次設(shè)置的值都是一樣的(都是1),hooks不會(huì)更新,同class

  •  場(chǎng)景七,父組件和子組件都使用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);                  }}              >                  測(cè)試              </Button>          </div>      );  }

子組件使用count

export default function App(props: Props) {      console.log(props, 'props');      return <div>{props.count}</div>;  }

結(jié)果:每次點(diǎn)擊測(cè)試,都會(huì)導(dǎo)致子組件重新render

怎么理解React hooks的渲染邏輯

子組件加入memo

function App(props: Props) {      console.log(props, 'props');      return <div>{props.count}</div>;  }  export default memo(App);

結(jié)果:

怎么理解React hooks的渲染邏輯

子組件并沒(méi)有觸發(fā)更新

這里跟第一個(gè)案例class的PureComponent不一樣,第一個(gè)案例class的PureComponent子組件此時(shí)會(huì)重新render,是因?yàn)楦附M件hooks確實(shí)每次更新都會(huì)導(dǎo)出新的value和state。這里是調(diào)用了一次,設(shè)置的都是相同的state.所以此時(shí)不更新

  •  場(chǎng)景八,父組件hook,子組件hook,使用useCallback緩存函數(shù)

父組件:

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);

結(jié)果:雖然我們使用了memo.但是點(diǎn)擊demo1,只有demo1后面的數(shù)字改變了,demo2沒(méi)有改變,點(diǎn)擊demo2,兩個(gè)數(shù)字都改變了。

那么我們不使用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>      );  }

子組件代碼不變,結(jié)果此時(shí)每次都會(huì)兩個(gè)數(shù)字都會(huì)跟著變。

怎么理解React hooks的渲染邏輯

官方對(duì)useCallback的解釋:

就是返回一個(gè)函數(shù),只有在依賴項(xiàng)發(fā)生變化的時(shí)候才會(huì)更新(返回一個(gè)新的函數(shù))

結(jié)論:

我們聲明的 handleClickButton1 是直接定義了一個(gè)方法,這也就導(dǎo)致只要是父組件重新渲染(狀態(tài)或者props更新)就會(huì)導(dǎo)致這里聲明出一個(gè)新的方法,新的方法和舊的方法盡管長(zhǎng)的一樣,但是依舊是兩個(gè)不同的對(duì)象,React.memo 對(duì)比后發(fā)現(xiàn)對(duì)象 props 改變,就重新渲染了。

const a =()=>{}  const b =()=>{}  a===b //false

這個(gè)道理大家都懂,不解釋了

  •  場(chǎng)景九,去掉依賴數(shù)組中的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}      >測(cè)試</Demo>    );  }

這樣count2的值永遠(yuǎn)都是0,那么這個(gè)組件就不會(huì)重導(dǎo)出setCount2這個(gè)方法,handleClickButton2這個(gè)函數(shù)永遠(yuǎn)不會(huì)變化,Button只會(huì)更新一次,就是Demo組件接受到的props從0到1到的時(shí)候.繼續(xù)點(diǎn)擊,count2也是0,但是props有一次從0-1的過(guò)程導(dǎo)致Demo子組件被更新,不過(guò)count2始終是0,這非常關(guān)鍵

  •  場(chǎng)景十,使用useMemo,緩存對(duì)象,達(dá)到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,沒(méi)有依賴value,只是依賴了count.

但是結(jié)果每次父組件修改了value的值后,雖然子組件沒(méi)有依賴value,而且使用了memo包裹,還是每次都重新渲染了

怎么理解React hooks的渲染邏輯

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就會(huì)導(dǎo)出一個(gè)新的count,const 就會(huì)聲明一個(gè)新的obj對(duì)象,即使用了memo包裹,也會(huì)被認(rèn)為是一個(gè)新的對(duì)象。

看看第二種的結(jié)果:

怎么理解React hooks的渲染邏輯

父組件更新,沒(méi)有再影響到子組件了。

到此,關(guān)于“怎么理解React hooks的渲染邏輯”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI