react hooks 和 react-redux hooks 應用場景

目前 ,Hooks 應該是 React 中最火的概念了,在閱讀這篇文章以前,但願你已經瞭解了基本的 Hooks 是什麼?react

下面就介紹一下簡單的使用場景redux

react hooks

useState

useState是react自帶的一個hook函數,它的做用就是用來聲明狀態變量。 useState這個函數接收的參數是咱們的狀態初始值(initial state), 它返回了一個數組,這個數組的第[0]項是當前當前的狀態值, 第[1]項是能夠改變狀態值的方法函數。數組

import React, { useState} from 'react';
function Example() {
     //useState的用法,分別是聲明、讀取、使用(修改)
    const [count, setCount] = useState(0) //數組結構
    const [age, setAge] = useState(18)
    const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
    return (
        <div> <button onClick={() => { setCount(count + 1) }}>count</button> <button onClick={() => { setAge(age + 1) }}>age</button> </div>
    );
}

export default Example;

複製代碼

基於 useState 的用法,咱們嘗試着本身實現一個 useState緩存

var _state; // 把 state 存儲在外面
function useState(initialValue) {
  _state = _state | initialValue; // 若是沒有 _state,說明是第一次執行,把 initialValue 複製給它
  function setState(newState) {
    _state = newState;
    render();
  }
  return [_state, setState];
}

複製代碼
useEffect

使用useEffect,能夠直接在函數組件內處理生命週期事件。 若是你熟悉 React class 的生命週期函數, 你能夠把 useEffect Hook 看作 componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個函數的組合性能優化

useEffect 使用須要注意的地方bash

  • 有兩個參數 callback 和 dependencies 數組
  • 若是 dependencies 不存在,那麼 callback 每次 render 都會執行
  • 若是 dependencies 存在,只有當它發生了變化, callback 纔會執行
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';

function useEffectTest() {
  useEffect(() => {
      
    // 默認狀況下,每次渲染後都會調用該函數
    console.log('render!');

    // 若是要實現 componentWillUnmount,
    // 在末尾處返回一個函數
    // React 在該函數組件卸載前調用該方法
    // 其命名爲 cleanup 是爲了代表此函數的目的,
    // 但其實也能夠返回一個箭頭函數或者給起一個別的名字。
    return function cleanup () {
        console.log('unmounting...');
    }
  })  
  return "useEffectTest";
}
複製代碼

阻止每次從新渲染都會執行 useEffect 若是但願 effect 較少運行,能夠提供第二個參數 - 值數組。 將它們視爲該effect的依賴關係。 若是其中一個依賴項自上次更改後,effect將再次運行。dom

const [value, setValue] = useState(0);

useEffect(() => {
  // 僅在 value 更改時更新
  console.log(value);
}, [value]) 
複製代碼
useContext

useContext 能夠實現共享狀態最大的改變是能夠在使用 Counter 的時候沒必要在包裹 Children 了,比方說咱們先建立一個上下文, 這個上下文裏頭有一個名爲 count 的 state,以及一個修改 count 的方法 setCountide

建立上下文函數

import React, { createContext, useState } from 'react';
import { Counter } from './Counter'
export const CountContext = createContext()
function Example2() {
    const [count, setCount] = useState(0)
    return (
        <div> <CountContext.Provider value={count,setCount}> <Counter /> </CountContext.Provider> </div> ) } export default Example2; 複製代碼

使用上下文性能

import React, { useContext} from 'react';
import {CountContext} from './Example2'
export function Counter() {
    const {count,setCount} = useContext(CountContext)  //一句話就能夠獲得count
    return (
        <h2>{count}</h2>
        <button onClick={() => { setCount(count + 1) }}>count</button>
    )
}
複製代碼
useReducer

Redux 的核心概念是,組件發出 action 與狀態管理器通訊。狀態管理器收到 action 之後,使用 Reducer 函數算出新的狀態

  • 簡單來講 reducer是一個函數(state, action) => newState: 接收當前應用的state和觸發的動做action,計算並返回最新的state。
import React, { useReducer } from 'react';
function reducer(state, action) {
    switch (action.type) {
        case 'add':
            return { count: state.count + 1 };
        case 'sub':
            return { count: state.count - 1 };
        default:
            return state
    }
}
function Example2() {
    const initialState = { count: 0 };
    const [state, dispatch] = useReducer(reducer,initialState)
    return (
        <div> <p>You clicked {state.count} times</p> <button onClick={() => { dispatch({ type: 'add'})}}>add</button> <button onClick={() => { dispatch({ type: 'sub'})}}>sub</button> </div>
    )
}

export default Example2;
複製代碼
useMemo

React 16.8.0 中發佈useMemo()

React.memo()是判斷一個函數組件的渲染是否重複執行

useMemo()是定義一段函數邏輯是否重複執行

useMemo(() => fn, inputs)跟useCallback(fn, inputs)效果同樣

const increase = useMemo(() => {
    if(value > 2) return value + 1;
}, [value]);
複製代碼
useRef

useRef的做用: 獲取DOM元素的節點 獲取子組件的實例 渲染週期之間共享數據的存儲(state不能存儲跨渲染週期的數據,由於state的保存會觸發組件重渲染)

import React, { useEffect, useRef } from 'react';
function App() {
  const h1Ref = useRef();
  useEffect(() => {
    console.log('useRef')
    console.log(h1Ref.current)
  }, [])
  return <h1 ref={h1Ref}>Hello World!</h1>
}
export default App;
複製代碼
useCallback
  • 建立一個回調方法的緩存,可讓咱們傳入子節點做爲props的時候,可讓其沒有變化,避免不必的渲染。

  • 根據輸入的inputs,也就是一個數組,內部的內容是否又變回,決定是返回存儲的老方法,仍是返回新的方法並記錄。

import React, { useState, useCallback, useEffect } from 'react';

const set = new Set();

function Callback() {
    const [count, setCount] = useState(1);
    const [val, setVal] = useState('');

    const callback = useCallback(() => {
        console.log(count);
    }, [count]);
    set.add(callback);


    return <div>
        <h4>{count}</h4>
        <h4>{set.size}</h4>
        <div>
            <button onClick={() => setCount(count + 1)}>+</button>
            <input value={val} onChange={event => setVal(event.target.value)}/>
        </div>
    </div>;
}

export default function Parent() {
    const [count, setCount] = useState(1);
    const [val, setVal] = useState('');

    const callback = useCallback(() => {
        return count;
    }, [count]);
    return <div>
        <h4>{count}</h4>
        <Child callback={callback}/>
        <div>
            <button onClick={() => setCount(count + 1)}>+</button>
            <input value={val} onChange={event => setVal(event.target.value)}/>
        </div>
    </div>;
}

function Child({ callback }) {
    const [count, setCount] = useState(() => callback());
    useEffect(() => {
        setCount(callback());
    }, [callback]);
    return <div>
        {count}
    </div>
}


複製代碼
useImperativeMethods

接受一個ref做爲參數,內部其實就是一個useLayoutEffect的調用。 主要就是在外部傳入的ref上掛載內容 ,實現相似ref掛載到ClassComponent上的效果

function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeMethods(ref, () : ({
    focus: () : {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);

複製代碼

React-Redux Hooks

useSelector
  • useSelector用於從Redux存儲的state中提取值並訂閱該state,這基本上相似於在hooks中實現的mapStateToProps函數

  • 首先,再也不提供ownProps API,而且應該使用useCallback或useMemo來經過自定義邏輯獲取它們

  • 其次,useSelector()第二個參數也是依賴數組,跟useEffect同樣。若是不提供第二個參數每次組件更新時都會從新計算;若是提供了依賴數組,只有依賴數組對應的值變動了以後,纔會觸發從新計算

  • 除此以外,redux 之前的性能優化邏輯一樣保留了下來,若是當前的props跟老的props相同,則組件將不會從新渲染。

  • 因爲React redux中使用的批處理更新的邏輯,致使同一組件中的多個useSelector()從新計算出state,只會讓組件從新渲染一次。所以,咱們能夠自由的在組件中useSelector(),而不用擔憂重複渲染的狀況

  • 在下面的例子中,咱們能夠將單個useSelector()分紅兩個獨立的(一個讀取title,另外一個讀取content)useSelector()他們在性能和渲染數量方面徹底相同

import React from 'react';
import { useSelector } from 'react-redux';
 
const Component = props => {
  const { title, content } = useSelector(state => ({
      title: state.title, 
      content: state.content
  }));
  
  return <div title={title}>{content}</div>;
複製代碼
useDispatch
  • 除了讀取store中的state,還要能dispatch actions來更新store中的state,useDispatch就是這樣一個API

  • 只要組件須要觸發redux action,那麼這個鉤子就是你須要的。不幸的是,mapDispatchToProps 被廢棄掉了 因此每當你想要dispatch action時,你須要使用dispatch(actionCreator())來調用它的action creator

  • 若是咱們初次使用這種方式,會顯得有點不太習慣,由於之前都是經過connect HOC來調用被包裝成prop的dispatch函數

  • 但hooks的方式會爲代碼帶來更多的清晰度。遺憾的是,若是咱們想要在事件處理函數裏面dispatch actions,必須建立一個匿名函數, 如:() => dispatch(actionCreator)。因爲匿名函數的性質,這將在每次從新渲染時得到新的引用

  • 若是將這個匿名函數做爲props傳遞給子組件組件,那麼子組件將每次都從新渲染。爲了優化性能,必須使該函數具備相同的引用, 解決方案是在useCallback中建立這個匿名函數。

import { useDispatch } from 'react-redux'
import { logout } from '../store/reducer'
    const dispatch = useDispatch()
    //登出
    const handleLogout = useCallback(() => {
        dispatch(logout())
    }, [dispatch])

複製代碼
相關文章
相關標籤/搜索