1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      React中Hooks的案例分析-創(chuàng)新互聯(lián)

      這篇文章給大家分享的是有關(guān)React中Hooks的案例分析的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

      為蒲城等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及蒲城網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計、蒲城網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!

      一個最簡單的Hooks

      首先讓我們看一下一個簡單的有狀態(tài)組件:

      class Example extends React.Component {
       constructor(props) {
       super(props);
       this.state = {
        count: 0
       };
       }
      
       render() {
       return (
        
        

      You clicked {this.state.count} times

         this.setState({ count: this.state.count + 1 })}>    Click me      
       );  } }

      我們再來看一下使用hooks后的版本:

      import { useState } from 'react';
      
      function Example() {
       const [count, setCount] = useState(0);
      
       return (
       
        

      You clicked {count} times

         setCount(count + 1)}>   Click me     
       ); }

      是不是簡單多了!可以看到,Example變成了一個函數(shù),但這個函數(shù)卻有自己的狀態(tài)(count),同時它還可以更新自己的狀態(tài)(setCount)。這個函數(shù)之所以這么了不得,就是因?yàn)樗⑷肓艘粋€hook--useState,就是這個hook讓我們的函數(shù)變成了一個有狀態(tài)的函數(shù)。

      除了useState這個hook外,還有很多別的hook,比如useEffect提供了類似于componentDidMount等生命周期鉤子的功能,useContext提供了上下文(context)的功能等等。

      Hooks本質(zhì)上就是一類特殊的函數(shù),它們可以為你的函數(shù)型組件(function component)注入一些特殊的功能。咦?這聽起來有點(diǎn)像被詬病的Mixins啊?難道是Mixins要在react中死灰復(fù)燃了嗎?當(dāng)然不會了,等會我們再來談兩者的區(qū)別。總而言之,這些hooks的目標(biāo)就是讓你不再寫class,讓function一統(tǒng)江湖。

      React為什么要搞一個Hooks?

      想要復(fù)用一個有狀態(tài)的組件太麻煩了!

      我們都知道react都核心思想就是,將一個頁面拆成一堆獨(dú)立的,可復(fù)用的組件,并且用自上而下的單向數(shù)據(jù)流的形式將這些組件串聯(lián)起來。但假如你在大型的工作項(xiàng)目中用react,你會發(fā)現(xiàn)你的項(xiàng)目中實(shí)際上很多react組件冗長且難以復(fù)用。尤其是那些寫成class的組件,它們本身包含了狀態(tài)(state),所以復(fù)用這類組件就變得很麻煩。

      那之前,官方推薦怎么解決這個問題呢?答案是:渲染屬性(Render Props)和高階組件(Higher-Order Components)。我們可以稍微跑下題簡單看一下這兩種模式。

      渲染屬性指的是使用一個值為函數(shù)的prop來傳遞需要動態(tài)渲染的nodes或組件。如下面的代碼可以看到我們的DataProvider組件包含了所有跟狀態(tài)相關(guān)的代碼,而Cat組件則可以是一個單純的展示型組件,這樣一來DataProvider就可以單獨(dú)復(fù)用了。

      import Cat from 'components/cat'
      class DataProvider extends React.Component {
       constructor(props) {
       super(props);
       this.state = { target: 'Zac' };
       }
      
       render() {
       return (
        
        {this.props.render(this.state)}   
       )  } }  (   )}/>

      雖然這個模式叫Render Props,但不是說非用一個叫render的props不可,習(xí)慣上大家更常寫成下面這種:

      ...
      
       {data => (
       
       )}
      

      高階組件這個概念就更好理解了,說白了就是一個函數(shù)接受一個組件作為參數(shù),經(jīng)過一系列加工后,最后返回一個新的組件。看下面的代碼示例,withUser函數(shù)就是一個高階組件,它返回了一個新的組件,這個組件具有了它提供的獲取用戶信息的功能。

      const withUser = WrappedComponent => {
       const user = sessionStorage.getItem("user");
       return props => ;
      };
      
      const UserPage = props => (
       
       

      My name is {props.user}!

       
      ); export default withUser(UserPage);

      以上這兩種模式看上去都挺不錯的,很多庫也運(yùn)用了這種模式,比如我們常用的React Router。但我們仔細(xì)看這兩種模式,會發(fā)現(xiàn)它們會增加我們代碼的層級關(guān)系。最直觀的體現(xiàn),打開devtool看看你的組件層級嵌套是不是很夸張吧。這時候再回過頭看我們上一節(jié)給出的hooks例子,是不是簡潔多了,沒有多余的層級嵌套。把各種想要的功能寫成一個一個可復(fù)用的自定義hook,當(dāng)你的組件想用什么功能時,直接在組件里調(diào)用這個hook即可。

      React中Hooks的案例分析

      生命周期鉤子函數(shù)里的邏輯太亂了吧!

      我們通常希望一個函數(shù)只做一件事情,但我們的生命周期鉤子函數(shù)里通常同時做了很多事情。比如我們需要在componentDidMount中發(fā)起ajax請求獲取數(shù)據(jù),綁定一些事件監(jiān)聽等等。同時,有時候我們還需要在componentDidUpdate做一遍同樣的事情。當(dāng)項(xiàng)目變復(fù)雜后,這一塊的代碼也變得不那么直觀。

      classes真的太讓人困惑了!

      我們用class來創(chuàng)建react組件時,還有一件很麻煩的事情,就是this的指向問題。為了保證this的指向正確,我們要經(jīng)常寫這樣的代碼:this.handleClick = this.handleClick.bind(this),或者是這樣的代碼:  

       ); }

      聲明一個狀態(tài)變量

      import { useState } from 'react';
      
      function Example() {
       const [count, setCount] = useState(0);

      useState是react自帶的一個hook函數(shù),它的作用就是用來聲明狀態(tài)變量。useState這個函數(shù)接收的參數(shù)是我們的狀態(tài)初始值(initial state),它返回了一個數(shù)組,這個數(shù)組的第[0]項(xiàng)是當(dāng)前當(dāng)前的狀態(tài)值,第[1]項(xiàng)是可以改變狀態(tài)值的方法函數(shù)。

      所以我們做的事情其實(shí)就是,聲明了一個狀態(tài)變量count,把它的初始值設(shè)為0,同時提供了一個可以更改count的函數(shù)setCount。

      上面這種表達(dá)形式,是借用了es6的數(shù)組解構(gòu)(array destructuring),它可以讓我們的代碼看起來更簡潔。不清楚這種用法的可以先去看下我的這篇文章30分鐘掌握ES6/ES2015核心內(nèi)容(上)。

      如果不用數(shù)組解構(gòu)的話,可以寫成下面這樣。實(shí)際上數(shù)組解構(gòu)是一件開銷很大的事情,用下面這種寫法,或者改用對象解構(gòu),性能會有很大的提升。具體可以去這篇文章的分析Array destructuring for multi-value returns (in light of React hooks),這里不詳細(xì)展開,我們就按照官方推薦使用數(shù)組解構(gòu)就好。

      let _useState = useState(0);
      let count = _useState[0];
      let setCount = _useState[1];

      讀取狀態(tài)值

      You clicked {count} times

      是不是超簡單?因?yàn)槲覀兊臓顟B(tài)count就是一個單純的變量而已,我們再也不需要寫成{this.state.count}這樣了。

      更新狀態(tài)

        setCount(count + 1)}>
       Click me
       

      當(dāng)用戶點(diǎn)擊按鈕時,我們調(diào)用setCount函數(shù),這個函數(shù)接收的參數(shù)是修改過的新狀態(tài)值。接下來的事情就交給react了,react將會重新渲染我們的Example組件,并且使用的是更新后的新的狀態(tài),即count=1。這里我們要停下來思考一下,Example本質(zhì)上也是一個普通的函數(shù),為什么它可以記住之前的狀態(tài)?

      一個至關(guān)重要的問題

      這里我們就發(fā)現(xiàn)了問題,通常來說我們在一個函數(shù)中聲明的變量,當(dāng)函數(shù)運(yùn)行完成后,這個變量也就銷毀了(這里我們先不考慮閉包等情況),比如考慮下面的例子:

      function add(n) {
       const result = 0;
       return result + 1;
      }
      
      add(1); //1
      add(1); //1

      不管我們反復(fù)調(diào)用add函數(shù)多少次,結(jié)果都是1。因?yàn)槊恳淮挝覀冋{(diào)用add時,result變量都是從初始值0開始的。那為什么上面的Example函數(shù)每次執(zhí)行的時候,都是拿的上一次執(zhí)行完的狀態(tài)值作為初始值?答案是:是react幫我們記住的。至于react是用什么機(jī)制記住的,我們可以再思考一下。

      假如一個組件有多個狀態(tài)值怎么辦?

      首先,useState是可以多次調(diào)用的,所以我們完全可以這樣寫:

      function ExampleWithManyStates() {
       const [age, setAge] = useState(42);
       const [fruit, setFruit] = useState('banana');
       const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

      其次,useState接收的初始值沒有規(guī)定一定要是string/number/boolean這種簡單數(shù)據(jù)類型,它完全可以接收對象或者數(shù)組作為參數(shù)。唯一需要注意的點(diǎn)是,之前我們的this.setState做的是合并狀態(tài)后返回一個新狀態(tài),而useState是直接替換老狀態(tài)后返回新狀態(tài)。最后,react也給我們提供了一個useReducer的hook,如果你更喜歡redux式的狀態(tài)管理方案的話。

      從ExampleWithManyStates函數(shù)我們可以看到,useState無論調(diào)用多少次,相互之間是獨(dú)立的。這一點(diǎn)至關(guān)重要。為什么這么說呢?

      其實(shí)我們看hook的“形態(tài)”,有點(diǎn)類似之前被官方否定掉的Mixins這種方案,都是提供一種“插拔式的功能注入”的能力。而mixins之所以被否定,是因?yàn)镸ixins機(jī)制是讓多個Mixins共享一個對象的數(shù)據(jù)空間,這樣就很難確保不同Mixins依賴的狀態(tài)不發(fā)生沖突。

      而現(xiàn)在我們的hook,一方面它是直接用在function當(dāng)中,而不是class;另一方面每一個hook都是相互獨(dú)立的,不同組件調(diào)用同一個hook也能保證各自狀態(tài)的獨(dú)立性。這就是兩者的本質(zhì)區(qū)別了。

      react是怎么保證多個useState的相互獨(dú)立的?

      還是看上面給出的ExampleWithManyStates例子,我們調(diào)用了三次useState,每次我們傳的參數(shù)只是一個值(如42,‘banana'),我們根本沒有告訴react這些值對應(yīng)的key是哪個,那react是怎么保證這三個useState找到它對應(yīng)的state呢?

      答案是,react是根據(jù)useState出現(xiàn)的順序來定的。我們具體來看一下:

       //第一次渲染
       useState(42); //將age初始化為42
       useState('banana'); //將fruit初始化為banana
       useState([{ text: 'Learn Hooks' }]); //...
      
       //第二次渲染
       useState(42); //讀取狀態(tài)變量age的值(這時候傳的參數(shù)42直接被忽略)
       useState('banana'); //讀取狀態(tài)變量fruit的值(這時候傳的參數(shù)banana直接被忽略)
       useState([{ text: 'Learn Hooks' }]); //...

      假如我們改一下代碼:

      let showFruit = true;
      function ExampleWithManyStates() {
       const [age, setAge] = useState(42);
       
       if(showFruit) {
       const [fruit, setFruit] = useState('banana');
       showFruit = false;
       }
       
       const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

      這樣一來,

       //第一次渲染
       useState(42); //將age初始化為42
       useState('banana'); //將fruit初始化為banana
       useState([{ text: 'Learn Hooks' }]); //...
      
       //第二次渲染
       useState(42); //讀取狀態(tài)變量age的值(這時候傳的參數(shù)42直接被忽略)
       // useState('banana'); 
       useState([{ text: 'Learn Hooks' }]); //讀取到的卻是狀態(tài)變量fruit的值,導(dǎo)致報錯

      鑒于此,react規(guī)定我們必須把hooks寫在函數(shù)的最外層,不能寫在ifelse等條件語句當(dāng)中,來確保hooks的執(zhí)行順序一致。

      什么是Effect Hooks?

      我們在上一節(jié)的例子中增加一個新功能:

      import { useState, useEffect } from 'react';
      
      function Example() {
       const [count, setCount] = useState(0);
      
       // 類似于componentDidMount 和 componentDidUpdate:
       useEffect(() => {
       // 更新文檔的標(biāo)題
       document.title = `You clicked ${count} times`;
       });
      
       return (
       
        

      You clicked {count} times

         setCount(count + 1)}>   Click me     
       ); }

      我們對比著看一下,如果沒有hooks,我們會怎么寫?

      class Example extends React.Component {
       constructor(props) {
       super(props);
       this.state = {
        count: 0
       };
       }
      
       componentDidMount() {
       document.title = `You clicked ${this.state.count} times`;
       }
      
       componentDidUpdate() {
       document.title = `You clicked ${this.state.count} times`;
       }
      
       render() {
       return (
        
        

      You clicked {this.state.count} times

         this.setState({ count: this.state.count + 1 })}>    Click me      
       );  } }

      我們寫的有狀態(tài)組件,通常會產(chǎn)生很多的副作用(side effect),比如發(fā)起ajax請求獲取數(shù)據(jù),添加一些監(jiān)聽的注冊和取消注冊,手動修改dom等等。我們之前都把這些副作用的函數(shù)寫在生命周期函數(shù)鉤子里,比如componentDidMount,componentDidUpdate和componentWillUnmount。而現(xiàn)在的useEffect就相當(dāng)與這些聲明周期函數(shù)鉤子的集合體。它以一抵三。

      同時,由于前文所說hooks可以反復(fù)多次使用,相互獨(dú)立。所以我們合理的做法是,給每一個副作用一個單獨(dú)的useEffect鉤子。這樣一來,這些副作用不再一股腦堆在生命周期鉤子里,代碼變得更加清晰。

      useEffect做了什么?

      我們再梳理一遍下面代碼的邏輯:

      function Example() {
       const [count, setCount] = useState(0);
      
       useEffect(() => {
       document.title = `You clicked ${count} times`;
       });

      首先,我們聲明了一個狀態(tài)變量count,將它的初始值設(shè)為0。然后我們告訴react,我們的這個組件有一個副作用。我們給useEffecthook傳了一個匿名函數(shù),這個匿名函數(shù)就是我們的副作用。在這個例子里,我們的副作用是調(diào)用browser API來修改文檔標(biāo)題。當(dāng)react要渲染我們的組件時,它會先記住我們用到的副作用。等react更新了DOM之后,它再依次執(zhí)行我們定義的副作用函數(shù)。

      這里要注意幾點(diǎn):

      第一,react首次渲染和之后的每次渲染都會調(diào)用一遍傳給useEffect的函數(shù)。而之前我們要用兩個聲明周期函數(shù)來分別表示首次渲染(componentDidMount),和之后的更新導(dǎo)致的重新渲染(componentDidUpdate)。

      第二,useEffect中定義的副作用函數(shù)的執(zhí)行不會阻礙瀏覽器更新視圖,也就是說這些函數(shù)是異步執(zhí)行的,而之前的componentDidMount或componentDidUpdate中的代碼則是同步執(zhí)行的。這種安排對大多數(shù)副作用說都是合理的,但有的情況除外,比如我們有時候需要先根據(jù)DOM計算出某個元素的尺寸再重新渲染,這時候我們希望這次重新渲染是同步發(fā)生的,也就是說它會在瀏覽器真的去繪制這個頁面前發(fā)生。

      useEffect怎么解綁一些副作用

      這種場景很常見,當(dāng)我們在componentDidMount里添加了一個注冊,我們得馬上在componentWillUnmount中,也就是組件被注銷之前清除掉我們添加的注冊,否則內(nèi)存泄漏的問題就出現(xiàn)了。

      怎么清除呢?讓我們傳給useEffect的副作用函數(shù)返回一個新的函數(shù)即可。這個新的函數(shù)將會在組件下一次重新渲染之后執(zhí)行。這種模式在一些pubsub模式的實(shí)現(xiàn)中很常見。看下面的例子:

      import { useState, useEffect } from 'react';
      
      function FriendStatus(props) {
       const [isOnline, setIsOnline] = useState(null);
      
       function handleStatusChange(status) {
       setIsOnline(status.isOnline);
       }
      
       useEffect(() => {
       ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
       // 一定注意下這個順序:告訴react在下次重新渲染組件之后,同時是下次調(diào)用ChatAPI.subscribeToFriendStatus之前執(zhí)行cleanup
       return function cleanup() {
        ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
       };
       });
      
       if (isOnline === null) {
       return 'Loading...';
       }
       return isOnline ? 'Online' : 'Offline';
      }

      這里有一個點(diǎn)需要重視!這種解綁的模式跟componentWillUnmount不一樣。componentWillUnmount只會在組件被銷毀前執(zhí)行一次而已,而useEffect里的函數(shù),每次組件渲染后都會執(zhí)行一遍,包括副作用函數(shù)返回的這個清理函數(shù)也會重新執(zhí)行一遍。所以我們一起來看一下下面這個問題。

      為什么要讓副作用函數(shù)每次組件更新都執(zhí)行一遍?

      我們先看以前的模式:

       componentDidMount() {
       ChatAPI.subscribeToFriendStatus(
        this.props.friend.id,
        this.handleStatusChange
       );
       }
      
       componentWillUnmount() {
       ChatAPI.unsubscribeFromFriendStatus(
        this.props.friend.id,
        this.handleStatusChange
       );
       }

      很清除,我們在componentDidMount注冊,再在componentWillUnmount清除注冊。但假如這時候props.friend.id變了怎么辦?我們不得不再添加一個componentDidUpdate來處理這種情況:

      ...
       componentDidUpdate(prevProps) {
       // 先把上一個friend.id解綁
       ChatAPI.unsubscribeFromFriendStatus(
        prevProps.friend.id,
        this.handleStatusChange
       );
       // 再重新注冊新但friend.id
       ChatAPI.subscribeToFriendStatus(
        this.props.friend.id,
        this.handleStatusChange
       );
       }
      ...

      看到了嗎?很繁瑣,而我們但useEffect則沒這個問題,因?yàn)樗诿看谓M件更新后都會重新執(zhí)行一遍。所以代碼的執(zhí)行順序是這樣的:

      1.頁面首次渲染
      2.替friend.id=1的朋友注冊
      3.突然friend.id變成了2
      4.頁面重新渲染
      5.清除friend.id=1的綁定
      6.替friend.id=2的朋友注冊
      ...

      怎么跳過一些不必要的副作用函數(shù)

      按照上一節(jié)的思路,每次重新渲染都要執(zhí)行一遍這些副作用函數(shù),顯然是不經(jīng)濟(jì)的。怎么跳過一些不必要的計算呢?我們只需要給useEffect傳第二個參數(shù)即可。用第二個參數(shù)來告訴react只有當(dāng)這個參數(shù)的值發(fā)生改變時,才執(zhí)行我們傳的副作用函數(shù)(第一個參數(shù))。

      useEffect(() => {
       document.title = `You clicked ${count} times`;
      }, [count]); // 只有當(dāng)count的值發(fā)生變化時,才會重新執(zhí)行`document.title`這一句

      當(dāng)我們第二個參數(shù)傳一個空數(shù)組[]時,其實(shí)就相當(dāng)于只在首次渲染的時候執(zhí)行。也就是componentDidMount加componentWillUnmount的模式。不過這種用法可能帶來bug,少用。

      還有哪些自帶的Effect Hooks?

      除了上文重點(diǎn)介紹的useState和useEffect,react還給我們提供來很多有用的hooks:

      • useContext

      • useReducer

      • useCallback

      • useMemo

      • useRef

      • useImperativeMethods

      • useMutationEffect

      • useLayoutEffect

      我不再一一介紹,大家自行去查閱官方文檔。

      怎么寫自定義的Effect Hooks?

      為什么要自己去寫一個Effect Hooks? 這樣我們才能把可以復(fù)用的邏輯抽離出來,變成一個個可以隨意插拔的“插銷”,哪個組件要用來,我就插進(jìn)哪個組件里,so easy!看一個完整的例子,你就明白了。

      比如我們可以把上面寫的FriendStatus組件中判斷朋友是否在線的功能抽出來,新建一個useFriendStatus的hook專門用來判斷某個id是否在線。

      import { useState, useEffect } from 'react';
      
      function useFriendStatus(friendID) {
       const [isOnline, setIsOnline] = useState(null);
      
       function handleStatusChange(status) {
       setIsOnline(status.isOnline);
       }
      
       useEffect(() => {
       ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
       return () => {
        ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
       };
       });
      
       return isOnline;
      }

      這時候FriendStatus組件就可以簡寫為:

      function FriendStatus(props) {
       const isOnline = useFriendStatus(props.friend.id);
      
       if (isOnline === null) {
       return 'Loading...';
       }
       return isOnline ? 'Online' : 'Offline';
      }

      簡直Perfect!假如這個時候我們又有一個朋友列表也需要顯示是否在線的信息:

      function FriendListItem(props) {
       const isOnline = useFriendStatus(props.friend.id);
      
       return (
       
        {props.friend.name}
       
       );
      }

      感謝各位的閱讀!關(guān)于“React中Hooks的案例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!


      分享標(biāo)題:React中Hooks的案例分析-創(chuàng)新互聯(lián)
      分享網(wǎng)址:http://www.ef60e0e.cn/article/pipcc.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        长丰县| 麦盖提县| 淳化县| 武隆县| 湘乡市| 沽源县| 松潘县| 亳州市| 定日县| 宁海县| 南投市| 包头市| 岐山县| 阳高县| 东阳市| 诸城市| 肃宁县| 通江县| 丘北县| 汕尾市| 连州市| 青阳县| 宁波市| 嘉鱼县| 咸丰县| 满洲里市| 灵璧县| 墨脱县| 汕尾市| 毕节市| 婺源县| 永泰县| 通许县| 惠来县| 阿克陶县| 宁化县| 新乐市| 会理县| 苏尼特左旗| 资阳市| 阜平县|