<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          「不容錯(cuò)過(guò)」手摸手帶你實(shí)現(xiàn) React Hooks

          共 6374字,需瀏覽 13分鐘

           ·

          2020-10-12 21:45

          轉(zhuǎn)自手寫 React Hookshttps://juejin.im/post/6872223515580481544

          手寫 React Hooks

          • Hooks 是 React 16.8 新增的特性,它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性
          • 凡是 use 開頭的 React API 都是 Hooks

          Hook 是什么

          Hook 是一個(gè)特殊的函數(shù),它可以讓你“鉤入” React 的特性。例如,useState 是允許你在 React 函數(shù)組件中添加 state 的 Hook。

          為什么使用 Hooks

          引用官網(wǎng)描述

          • 在組件之間復(fù)用狀態(tài)邏輯很難

          可能要用到 render props (渲染屬性)或者 HOC(高階組件),但無(wú)論是渲染屬性,還是高階組件,都會(huì)在原先的組件外包裹一層父容器(一般都是 div 元素).如果你在 React DevTools 中觀察過(guò) React 應(yīng)用,你會(huì)發(fā)現(xiàn)由 providers,consumers,高階組件,render props 等其他抽象層組成的組件會(huì)形成“嵌套地獄”。

          • 復(fù)雜組件變得難以理解

          組件常常在 componentDidMount 和 componentDidUpdate 中獲取數(shù)據(jù)。但是,同一個(gè) componentDidMount 中可能也包含很多其它的邏輯,如設(shè)置事件監(jiān)聽(tīng),而之后需在 componentWillUnmount 中清除。相互關(guān)聯(lián)且需要對(duì)照修改的代碼被進(jìn)行了拆分,而完全不相關(guān)的代碼卻在同一個(gè)方法中組合在一起。如此很容易產(chǎn)生 bug

          • 難以理解的 class

          this 指向問(wèn)題:父組件給子組件傳遞函數(shù)時(shí),必須綁定 this

          Hook 規(guī)則

          • 只能在函數(shù)內(nèi)部的最外層調(diào)用 Hook,不要在循環(huán)、條件判斷或者子函數(shù)中調(diào)用
          • 只在 React 函數(shù)中調(diào)用 Hook 在 React 的函數(shù)組件中調(diào)用 Hook 在自定義 Hook 中調(diào)用其他 Hook

          利用 eslint 做 hooks 規(guī)則檢查

          使用 eslint-plugin-react-hooks 來(lái)檢查代碼錯(cuò)誤

          ????{
          ??????"plugins":?["react-hooks"],
          ??????//?...
          ??????"rules":?{
          ????????"react-hooks/rules-of-hooks":?'error',//?檢查?Hook?的規(guī)則
          ????????"react-hooks/exhaustive-deps":?'warn'?//?檢查?effect?的依賴
          ??????}
          ????}

          useState

          useState 會(huì)返回一個(gè)數(shù)組:一個(gè) state,一個(gè)更新 state 的函數(shù)。

          類似 class 組件的 this.setState,但是它不會(huì)把新的 state 和舊的 state 進(jìn)行合并,而是直接替換

          ????//?保存狀態(tài)的數(shù)組
          ????let?hookStates?=?[];
          ????//?索引
          ????let?hookIndex?=?0;
          ????
          ????function?useState(initialState)?{
          ??????hookStates[hookIndex]?=?hookStates[hookIndex]?||?initialState;
          ??????//?利用閉包維護(hù)函數(shù)調(diào)用位置
          ??????let?currentIndex?=?hookIndex;
          ??????function?setState(newState)?{
          ????????//?判斷傳入的state是否為函數(shù),如果是把prevState傳入
          ????????if?(typeof?newState?===?"function")?{
          ??????????//?重新復(fù)制給newState
          ??????????newState?=?newState(hookStates[hookIndex]);
          ????????}
          ????????//?更新state
          ????????hookStates[currentIndex]?=?newState;
          ????????//?觸發(fā)視圖更新
          ????????render();
          ??????}
          ??????//?返回?cái)?shù)組形式,解構(gòu)可寫成任意變量
          ??????return?[hookStates[hookIndex++],?setState];
          ????}

          useEffect

          useEffect 就是一個(gè) Effect Hook,給函數(shù)組件增加了操作副作用的能力。它跟 class 組件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不過(guò)被合并成了一個(gè) API

          與 componentDidMount 或 componentDidUpdate 不同,使用 useEffect 調(diào)度的 effect 不會(huì)阻塞瀏覽器更新視圖,這讓你的應(yīng)用看起來(lái)響應(yīng)更快。在特殊情況(例如測(cè)量布局),有單獨(dú)的 useLayoutEffect Hook,使用與 useEffect 相同

          ????//保存狀態(tài)的數(shù)組
          ????let?hookStates?=?[];
          ????//索引
          ????let?hookIndex?=?0;
          ????
          ????function?useEffect(callback,?dependencies)?{
          ??????if?(hookStates[hookIndex])?{
          ????????//?非初始調(diào)用
          ????????let?lastDependencies?=?hookStates[hookIndex];
          ????????//?判斷傳入依賴項(xiàng)跟上一次是否相同
          ????????let?same?=?dependencies.every(
          ??????????(item,?index)?=>?item?===?lastDependencies[index]
          ????????);
          ????????if?(same)?{
          ??????????hookIndex++;
          ????????}?else?{
          ??????????hookStates[hookIndex++]?=?dependencies;
          ??????????callback();
          ????????}
          ??????}?else?{
          ????????//?初始調(diào)用
          ????????hookStates[hookIndex++]?=?dependencies;
          ????????callback();
          ??????}
          ????}

          useMemo

          允許你通過(guò)「記住」上一次計(jì)算結(jié)果的方式在多次渲染的之間緩存計(jì)算結(jié)果

          使得控制具體子節(jié)點(diǎn)何時(shí)更新變得更容易,減少了對(duì)純組件的需要

          ????//?保存狀態(tài)的數(shù)組
          ????let?hookStates?=?[];
          ????//?索引
          ????let?hookIndex?=?0;
          ????
          ????function?useMemo(factory,?dependencies)?{
          ??????if?(hookStates[hookIndex])?{
          ????????//?非首次
          ????????let?[lastMemo,?lastDependencies]?=?hookStates[hookIndex];
          ????
          ????????//?判斷傳入依賴項(xiàng)跟上一次是否相同
          ????????let?same?=?dependencies.every(
          ??????????(item,?index)?=>?item?===?lastDependencies[index]
          ????????);
          ????????if?(same)?{
          ??????????hookIndex++;
          ??????????return?lastMemo;
          ????????}?else?{
          ??????????//?只要有一個(gè)依賴變量不一樣的話
          ??????????let?newMemo?=?factory();
          ??????????hookStates[hookIndex++]?=?[newMemo,?dependencies];
          ??????????return?newMemo;
          ????????}
          ??????}?else?{
          ????????//?首次調(diào)用
          ????????let?newMemo?=?factory();
          ????????hookStates[hookIndex++]?=?[newMemo,?dependencies];
          ????????return?newMemo;
          ??????}
          ????}

          useCallback

          允許你在重新渲染之間保持對(duì)相同的回調(diào)引用以使得 shouldComponentUpdate 繼續(xù)工作

          ????//?保存狀態(tài)的數(shù)組
          ????let?hookStates?=?[];
          ????//?索引
          ????let?hookIndex?=?0;
          ????
          ????function?useCallback(callback,?dependencies)?{
          ??????if?(hookStates[hookIndex])?{
          ????????//?非首次
          ????????let?[lastCallback,?lastDependencies]?=?hookStates[hookIndex];
          ????
          ????????let?same?=?dependencies.every(
          ??????????(item,?index)?=>?item?===?lastDependencies[index]
          ????????);
          ????????if?(same)?{
          ??????????hookIndex++;
          ??????????return?lastCallback;
          ????????}?else?{
          ??????????//?只要有一個(gè)依賴變量不一樣的話
          ??????????hookStates[hookIndex++]?=?[callback,?dependencies];
          ??????????return?callback;
          ????????}
          ??????}?else?{
          ????????//?首次調(diào)用
          ????????hookStates[hookIndex++]?=?[callback,?dependencies];
          ????????return?callback;
          ??????}
          ????}

          memo

          ????function?memo(OldFunctionComponent)?{
          ??????return?class?extends?React.PureComponent?{
          ????????render()?{
          ??????????return?;
          ????????}
          ??????};
          ????}

          useContext

          接收一個(gè) context 對(duì)象(React.createContext 的返回值)并返回該 context 的當(dāng)前值 useContext(MyContext) 只是讓你能夠讀取 context 的值以及訂閱 context 的變化。仍然需要在上層組件樹中使用 來(lái)為下層組件提供 context

          ????function?useContext(context)?{
          ??????return?context._currentValue;
          ????}
          ????
          ????//?父組件
          ????const?CountCtx?=?React.createContext();
          ????function?ParentComp()?{
          ??????const?[state,?setState]?=?React.useState({?number:?0?});
          ??????return?(
          ????????
          ??????????
          ????????
          ??????);
          ????}
          ????
          ????//?子組件
          ????function?Child()?{
          ??????let?{?state,?setState?}?=?useContext(CountCtx);
          ??????return?(
          ????????

          ??????????

          {state.number}


          ???????????setState({?number:?state.number?+?1?})}>
          ????????????add
          ??????????
          ????????

          ??????);
          ????}

          useRef

          useRef 返回一個(gè)可變的 ref 對(duì)象,其 current 屬性被初始化為傳入的參數(shù) useRef 返回的 ref 對(duì)象在組件的整個(gè)生命周期內(nèi)保持不變,也就是說(shuō)每次重新渲染函數(shù)組件時(shí),返回的 ref 對(duì)象都是同一個(gè)(注意使用 React.createRef ,每次重新渲染組件都會(huì)重新創(chuàng)建 ref)

          ????let?lastRef;
          ????
          ????function?useRef(value)?{
          ??????lastRef?=?lastRef?||?{?current:?value?};
          ??????return?lastRef;
          ????}

          useReducer

          useReducer 和 redux 中 reducer 很像 useState 內(nèi)部就是靠 useReducer 來(lái)實(shí)現(xiàn)的

          ????//?保存狀態(tài)的數(shù)組
          ????let?hookStates?=?[];
          ????//?索引
          ????let?hookIndex?=?0;
          ????
          ????function?useReducer(reducer,?initialState)?{
          ??????hookStates[hookIndex]?=?hookStates[hookIndex]?||?initialState;
          ????
          ??????let?currentIndex?=?hookIndex;
          ??????function?dispatch(action)?{
          ????????hookStates[currentIndex]?=?reducer
          ????????????reducer(hookStates[currentIndex],?action)
          ??????????:?action;
          ????????//?觸發(fā)視圖更新
          ????????render();
          ??????}
          ??????return?[hookStates[hookIndex++],?dispatch];
          ????}
          ????
          ????//?useState可以使用useReducer改寫
          ????function?useState(initialState)?{
          ??????return?useReducer(null,?initialState);
          ????}

          參考

          Hook 規(guī)則

          React Hooks 詳解 【近 1W 字】+ 項(xiàng)目實(shí)戰(zhàn)

          推薦

          React Hooks 父組件中獲取子組件實(shí)例值

          React Hooks 中 useRef 的優(yōu)雅使用


          后記

          如果你喜歡探討技術(shù),或者對(duì)本文有任何的意見(jiàn)或建議,非常歡迎加魚頭微信好友一起探討,當(dāng)然,魚頭也非常希望能跟你一起聊生活,聊愛(ài)好,談天說(shuō)地。魚頭的微信號(hào)是:krisChans95 也可以掃碼關(guān)注公眾號(hào),訂閱更多精彩內(nèi)容。



          瀏覽 60
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  很很日免费视频 | 人人色人人摸 | 美女高潮视频免费在线观看 | 欧美色图欧美色图 | 中文字幕日产av 中文字幕在线资源 |