目錄
- useReducer
- 案例1:useReducer不帶初始化函數
- 案例2:useReducer帶初始化函數
- 注意事項1:dispatch函數不會改變正在運行的代碼的狀態
- 注意事項2:獲取dispatch函數觸發后 JavaScript 變量的值
- 注意事項3:觸發了reducer,但頁面沒有更新

React官方文檔
useReducer
useReducer是一個 React Hook,可讓你向組件添加一個Reducer 。
用法:
const [state, dispatch] = useReducer(reducer, initialArg, init?)
- reducer:指定狀態如何更新的 Reducer 函數,接受兩個參數state(狀態)和action(操作)兩個參數,并返回下一個狀態
- initialArg:初始值,可以是任何類型的值
- 可選 init:應返回初始狀態的初始化函數。如果未指定,則將初始狀態設置為initialArg。否則,將初始狀態設置為調用的結果init(initialArg)
useReducer返回一個包含兩個值的數組:
- state(當前狀態):在第一次渲染期間,它被設置為init(initialArg)或initialArg(如果沒有init)
- dispatch:該dispatch函數可讓您將狀態更新為不同的值并觸發重新渲染
案例1:useReducer不帶初始化函數
步驟:
1、定義一個reducer函數,根據不同的action返回不同的狀態
2、組件中調用userReducer(reducer,initialArg)
3、調用dispatch({type:“INC”})通知reducer產生一個新的狀態,隨后更新UI
const idata = {count:0};
function reducer(state, action) {console.log(state,"state")console.log(action,"action")switch (action.type) {case "INC":return {count:state.count+1}case "DEC":return {count:state.count-1}case "SET":return {count:action.payload}default:return {count:idata}}
}
function App() {const [state, dispatch] = useReducer(reducer, idata);return (<div className="App">this is App{state.count}<button onClick={() => dispatch({ type: "INC" })}>+</button><button onClick={() => dispatch({ type: "DEC" })}>-</button><button onClick={() => dispatch({ type: "SET", payload: 100 })}>update</button></div>);
}export default App;
案例2:useReducer帶初始化函數
設置initData為初始化函數,設置state初始狀態
#App.js
import Son from "./Son.js";
function App() {return (<div className="App"><Son idata={{count:1}}></Son></div>);}export default App;
#Son.js
import { useReducer } from "react";const initData=()=>{return {count:0}
}function reducer(state, action) {console.log(state,"state")console.log(action,"action")switch (action.type) {case "INC":return {count:state.count+1}case "DEC":return {count:state.count-1}case "SET":return {count:action.payload}default:return initData() }
}const Son = ({idata})=> {console.log(idata,"idata")const [state, dispatch] = useReducer(reducer, idata,initData);return (<div className="App">this is App<div>Count: {state.count}</div><button onClick={() => dispatch({ type: "INC" })}>+</button><button onClick={() => dispatch({ type: "default" })}>default</button><button onClick={() => dispatch({ type: "DEC" })}>-</button><button onClick={() => dispatch({ type: "SET", payload: 100 })}>update</button></div>);
}export default Son;
注意事項1:dispatch函數不會改變正在運行的代碼的狀態
點擊update按鈕,handler函數觸發之后,頁面Count顯示為100,但是打印出來state.count為0
dispatch函數不會改變正在運行的代碼的狀態,更新狀態會請求使用新狀態值進行另一次渲染,但不會影響state已在運行的事件處理程序中的 JavaScript 變量。
#Son.js
import { useReducer } from "react";
const initData = () => {return { count: 0 }
}
function reducer(state, action) {switch (action.type) {case "INC":return { count: state.count + 1 }case "DEC":return { count: state.count - 1 }case "SET":return { count: action.payload }default:return initData()}
}const Son = ({ idata }) => {
const [state, dispatch] = useReducer(reducer, idata, initData);const handler =()=>{dispatch({ type: "SET", payload: 100 })console.log(state.count,"state")setTimeout(()=>{console.log(state.count,"state")},1000)}return (<div className="App">this is App<div>Count: {state.count}</div><button onClick={() => dispatch({ type: "INC" })}>+</button><button onClick={() => dispatch({ type: "default" })}>default</button><button onClick={() => dispatch({ type: "DEC" })}>-</button><button onClick={() => handler()}>update</button></div >);
}export default Son;
注意事項2:獲取dispatch函數觸發后 JavaScript 變量的值
執行reducer(state, action)之后,就可以拿到最新的變量的值
const handler =()=>{let action = { type: "SET", payload: 100 };dispatch(action)console.log(state,"state") //打印0setTimeout(()=>{console.log(state,"state") //打印0},1000)const nextState = reducer(state, action);console.log(nextState,'nextState') //打印100}
注意事項3:觸發了reducer,但頁面沒有更新
直接更改狀態中的對象或數組,并不會重新渲染。因為下一個狀態等于前一個狀態,則React 將忽略您的更新Object.is,指向的還是同一個引用地址。所以需要始終更新狀態中的對象和狀態中的數組。如下:
function reducer(state, action) {switch (action.type) {case 'incremented_age': {// ? Correct: creating a new objectreturn {...state,age: state.age + 1};}case 'changed_name': {// ? Correct: creating a new objectreturn {...state,name: action.nextName};}// ...}
}