Hook鉤子函式--useReducer
阿新 • • 發佈:2021-11-22
1.介紹
(1)作用:“勾住”某些自定義資料對應的dispatch所引發的資料更改事件。useReducer可以替代useState,實現更為複雜邏輯的資料修改。
(2)解決什麼問題:useReducer是useState的升級版(實際上應該是原始版),可以實現複雜邏輯修改,而不是像useState那樣只是直接賦值修改。
2.useReducer基礎用法
useReducer(reducer,initialValue)函式通常傳入2個引數,第1個引數為我們定義的一個“由dispatch引發的資料修改處理函式”,第2個引數為自定義資料的預設值,useReducer函式會返回自定義變數的引用和該自定義變數對應的“dispatch”。 import React, { useReducer } from 'react'; //引入useReducer //定義好“事件處理函式” reducer function reducer(state, action) { switch (action) { case 'xx': return xxxx; case 'xx': return xxxx; default: return xxxx; } }function Component(){ //宣告一個變數xxx,以及對應修改xxx的dispatch //將事件處理函式reducer和預設值initialValue作為引數傳遞給useReducer const [xxx, dispatch] = useReducer(reducer, initialValue);
//若想獲取xxx的值,直接使用xxx即可 //若想修改xxx的值,通過dispatch來修改 dispatch('xx'); } 3.基礎案例: 若某React元件內部有一個變數count,預設值為0,有3個button,點選之後分別可以修改count的值。3個按鈕具體的功能為:第1個button點選之後count+1,第2個button點選之後count -1,第3個button點選之後 count x 2 (翻倍)。
import React, { useReducer } from 'react';
function reducer(state,action){ switch(action){ case 'add': return state + 1; case 'sub': return state - 1; case 'mul': return state * 2; default: console.log('what?'); return state; } }
function CountComponent() { const [count, dispatch] = useReducer(reducer,0);
return <div> {count} <button onClick={() => {dispatch('add')}} >add</button> <button onClick={() => {dispatch('sub')}} >sub</button> <button onClick={() => {dispatch('mul')}} >mul</button> </div>; }
export default CountComponent; 如果希望按鈕點選之後,能夠自主的控制增加多少,減少多少,或者乘以多少 import React, { useReducer } from 'react';
function reducer(state,action){ //根據action.type來判斷該執行哪種修改 switch(action.type){ case 'add': //count 最終加多少,取決於 action.param 的值 return state + action.param; case 'sub': return state - action.param; case 'mul': return state * action.param; default: console.log('what?'); return state; } }
function getRandom(){ return Math.floor(Math.random()*10); }
function CountComponent() { const [count, dispatch] = useReducer(reducer,0);
return <div> {count} <button onClick={() => {dispatch({type:'add',param:getRandom()})}} >add</button> <button onClick={() => {dispatch({type:'sub',param:getRandom()})}} >sub</button> <button onClick={() => {dispatch({type:'mul',param:getRandom()})}} >mul</button> </div>; }
export default CountComponent; 4.useReducer高階用法 (1)使用useReducer來管理複雜型別的資料 舉例,若某元件內通過ajax請求資料,獲取最新一條站內簡訊文字,需要元件顯示整個ajax過程及結果: ①當ajax開始請求時,介面顯示“loading...”; ②當ajax請求發生錯誤時,介面顯示“wrong!”; ③當ajax請求成功獲取資料時,介面顯示獲取到的資料內容; 虛擬碼: const initralData = {loading: true,result: '',error: false}; const reducer = (state, action) => { switch (action.type) { case 'succes': return {loading:false,result:action.res,error:false} case 'error': return {loading:false,error:true} } } function Component() { const [state, dispatch] = useReducer(reducer, initralData); { //ajax請求成功情況下 dispatch({type:'succes',res:'You have a good news!'}); //ajax請求錯誤情況下 dispatch({type:'error'}); } return <div> {state.loading ? 'loading...' : state.result} {state.error ? 'wrong!' : null} </div> } (2)使用useContext和useReducer實現全域性共享資料 實現的原理:用useContext實現“獲取全域性資料”;用userReducer實現“修改全域性資料” 實現的思路:① 用React.createContext()定義一個全域性資料物件 ②在父元件中用userReducer定義全域性變數xx和負責丟擲事件的dispatch ③在父元件之外,定義負責具體修改全域性變數的處理函式reducer,根據修改xx事件型別和引數,執行修改xx的值 ④在父元件中用<XxxContext.Provider value={{xx,dispathc}}>標籤把全域性共享資料和負責丟擲修改xx的dispatch暴露給子元件 ⑤在子元件中用useContext獲取全域性變數 ⑥在子元件中用xxContext.dispatch去丟擲修改xx的事件,攜帶修改事件型別和引數 假如有全域性變數資料count,有不同的子元件均可以獲取並且修改全域性變數count CountContext.js: ①共享物件: import React from 'react'; const CountContext = React.createContext(); export default CountContext; 父元件: import React, { useReducer } from 'react'; import CountContext from './CountContext'; import ComponentA from './ComponentA'; import ComponentB from './ComponentB'; import ComponentC from './ComponentC';
const initialCount = 0; //定義count的預設值 // 修改count事件處理函式,根據u修改引數進行處理 //③在父元件之外,定義負責具體修改全域性變數的處理函式reducer,根據修改xx事件型別和引數,執行修改xx的值; function reducer(state, action) { switch (action.type) { case 'add': return state + action.param; case 'sub': return state - action.param; case 'mul': return state * action.param; case 'reset': return initialCount; default: console.log("what?"); return state; } } export default function father() { // ②在父元件中用 userReducer 定義全域性變數count和負責丟擲修事件的dispatch; const [count, dispatch] = useReducer(reducer, initialCount); // value={{ count, dispatch }是整個程式碼的核心,把將count、dispatch暴露給所有的子元件 // ④在父元件中用 <XxxContext.Provider value={{xx,dispathc}}> 標籤把 全域性共享資料和負責丟擲修改xx的dispatch 暴露給子元件; return <CountContext.Provider value={{ count, dispatch }}> <div> ParentComponent - count = {count} <ComponentA /> <ComponentB /> <ComponentC/> </div> </CountContext.Provider> } 子元件: import React,{ useState, useContext } from 'react'; import CountContext from './CountContext'; export default function ComponentA() { const [param, setParam] = useState(1); // 引入全域性共享物件,獲取全域性變數count,以及修改count對應的dispatch //⑤在子元件中用 useContext 獲取全域性變數; const countContext = useContext(CountContext) const inputChangeHandler = (eve) => { setParam(eve.target.value) } const doHandler = () => { //若想修改全域性count,先獲取count對應的修改丟擲事件物件dispatch,然後通過dispatch將修改內容丟擲 //丟擲的修改內容為:{type:'add',param:xxx},即告訴count的修改事件處理函式,本次修改的型別為add,引數是param //這裡的add和param完全是根據自己實際需求自己定義的 // ⑥在子元件中用 xxContext.dispatch 去丟擲修改xx的事件,攜帶修改事件型別和引數; countContext.dispatch({type:'add',param:Number(param)}); } const resetHandler = () => { //⑥在子元件中用 xxContext.dispatch 去丟擲修改xx的事件,攜帶修改事件型別和引數; countContext.dispatch({type:'reset'}); } return <div> ComponentA - count={countContext.count} <input type='number' value={param} onChange={inputChangeHandler} /> <button onClick={doHandler}>add {param}</button> <button onClick={resetHandler}>reset</button> </div> }