天天看點

React hook 相關内容一、useReducer 與 useState二、為什麼 useState 傳回的是個數組,而不是對象三、副作用四、為什麼要使用 HOOK五、useState 閉包六、useReducer七、useContext八、useEffect九、useMemo十、memo十一、useCallback十二、useRef十三、自定義 Hook十四、路由 Hook十五、手寫 useState十六、useEffect十七、useReducer相關連結

一、useReducer 與 useState

useReducer 可以傳給子元件個 dispatch 函數,子元件可以通過傳遞不同的 action,來達到不一樣的處理(比如加 1 或 減 1),而用 useState 就要定義多個并且傳遞多個

二、為什麼 useState 傳回的是個數組,而不是對象

因為數組隻是定義了個順序,元件方要使用什麼名字都可以;

對象則定義死了 key,并且無法在一個元件裡填寫多個,因為一個元件的 state 命名要唯一

三、副作用

隻要不是将資料轉成視圖,像是 ajax 請求,為 dom 元素添加事件,設定定時器

四、為什麼要使用 HOOK

  1. 類元件缺少邏輯複用機制

    包裹類元件,增加了元件層級,增加了調試的難度以及運作效率

  2. 類元件經常會變得很複雜很難以維護
    • 将一組相幹的業務邏輯拆分到了多個生命周期函數中,比如建立與銷毀寫在不同的生命周期
    • 在一個生命周期函數記憶體在多個不相幹的業務邏輯,比如又是 ajax 請求,又要設定标題
  3. 類成員方法不能保證this 指向的正确性

五、useState 閉包

  • 用于為函數元件引入狀态
  • 參數除了是任意資料類型外,也可以是個函數,用于初始值是動态值的情況
  • 函數隻會被調用一次,相當于隻會在元件初次渲染時執行,而在元件更新時并不會執行, 用于初始值是由外部傳入的場景
const [count,setCount] = useState(() => {
    return props.count || 0
})
           
  • 如果在函數體裡寫成如下,那麼元件更新時,count 的值又會被設定為初始值,更新失效
const countNum = props.count || 0
const [count,setCount] = useState(countNum)
           
  • 設定狀态值的方法可以是一個值也可以是個函數,是異步的
setCount(count => {
    return count + 1
})
           

六、useReducer

比起 useState,減少傳遞函數給子元件,通過參數的值來做不同的效果,而不像 useState 的 更改做的事情比較單一

不需要傳遞多個修改資料的方法,比如數值加1,或減1,而是直接将 dispatch(useReducer 的第二個參數)傳給子元件,子元件傳遞不同的 action 來觸發

七、useContext

在跨元件層級擷取資料時簡化擷取資料的代碼

相當于将 countContext.consumer 簡化成 useContext(countContext)

八、useEffect

第二個參數,不傳時任何資料發生改變都會觸發回調函數,

傳遞數組時,表示指定資料發生變化時才會觸發回調函數

useEffect(() => {
    document.title = count
},[count])
           

useEffect 的參數函數不能是異步函數,因為 useEffect 要傳回清理資源的函數,如果是異步函數就變成了傳回 promise,可以改成自執行函數來解決

useEffect(() => {
    (async () => {
        await axios.get()
    })()
})
           

九、useMemo

監測某個值的變化,根據變化值計算新值

會緩存計算結果 ,如果監測值沒有發生變化,即使元件重新渲染,也不會重新計算。此行為可以有助于避免在每個渲染上進行昂貴的計算

const result = useMemo(() => {
    return count
},[count])
           

十、memo

性能優化,如果本元件中的資料沒有發生變化,阻止元件更新,類似于類元件中的 PureCompoent 與 shouldComponentUpdate,但 memo 預設隻能監聽 props 更改

function Counter() {
    return <div>11</div>
}
export default memo(Counter)
           

十一、useCallback

性能優化,緩存函數,使元件重新渲染時得到相同的函數執行個體

父子元件

十二、useRef

擷取 DOM 元素對象,對象會有個 current 屬性指向 DOM 元素

const userName = useRef()
return <div ref={userName}></div>
           

儲存資料(跨元件周期)

即使元件重新渲染,儲存的資料仍然還在,

儲存的資料被更改不會觸發元件重新渲染

用處:

  1. 在 useEffect 差別 didMount 還是 didUpdate 時,
  2. 成員清單下拉加載更多時,
  3. 用于存儲 pageNo 定時器

十三、自定義 Hook

  • 标準的封裝和共享邏輯的方式 是個函數,
  • 其名稱是以 use 開頭
  • 其實就是邏輯和内置 Hook 的組合

    共享邏輯:有共同的業務邏輯,比如兩個元件都有擷取文章的需求,那麼就可以将擷取文章抽成自定義 hook

十四、路由 Hook

useHistory useLocation useRouteMatch useParams(路由參數)

// props 輸出的對象,有以下屬性
history
location
match
           

十五、手寫 useState

let state = [];
let setters = [];
let stateIndex = 0;

function createSetter (index) {
  return function (newState) {
    state[index] = newState;
    render ();
  }
}

function useState (initialState) {
  state[stateIndex] = state[stateIndex] ? state[stateIndex] : initialState;
  setters.push(createSetter(stateIndex));
  let value = state[stateIndex];
  let setter = setters[stateIndex];
  stateIndex++;
  return [value, setter];
}

function render () {
  stateIndex = 0;
  effectIndex = 0;
  ReactDOM.render(<App />, document.getElementById('root'));
}
           

十六、useEffect

// 上一次的依賴值
let prevDepsAry = [];
let effectIndex = 0;

function useEffect(callback, depsAry) {
  // 判斷callback是不是函數
  if (Object.prototype.toString.call(callback) !== '[object Function]') throw new Error('useEffect函數的第一個參數必須是函數');
  // 判斷depsAry有沒有被傳遞
  if (typeof depsAry === 'undefined') {
    // 沒有傳遞
    callback();
  } else {
    // 判斷depsAry是不是數組
    if (Object.prototype.toString.call(depsAry) !== '[object Array]') throw new Error('useEffect函數的第二個參數必須是數組');
    // 擷取上一次的狀态值
    let prevDeps = prevDepsAry[effectIndex];
    // 将目前的依賴值和上一次的依賴值做對比 如果有變化 調用callback
    let hasChanged = prevDeps ? depsAry.every((dep, index) => dep === prevDeps[index]) === false : true;
    // 判斷值是否有變化
    if (hasChanged) {
      callback();
    }
    // 同步依賴值
    prevDepsAry[effectIndex] = depsAry;
    effectIndex++;
  }
}
           

十七、useReducer

function useReducer (reducer, initialState) {
  const [state, setState] = useState(initialState);
  function dispatch (action) {
    const newState = reducer(state, action);
    setState(newState);
  }
  return [state, dispatch];
}
           

相關連結

react Hook 之 memo,useCallback,useMemo 性能優化

useRef詳細總結

繼續閱讀