useRecucer与useState一样,都是React hooks中引入用于状态管理的,更具体点,useState是利用useReducer来实现的。
使用useReducer很简单,只需要 :
1) 引入 useReducer: import {useReducer} from 'react'
2)定义initState状态与reducer函数;其中reducer函数包含currentState与action两 个参数,并根据action,返回新的状态;
3)使用 useReducer(reducer, initState, init),返回当前状态currentState和一个执行相应action的dispatch;
按照以上步骤,使用useReducer实现一个计数器,主要有increament, decrement, reset功能。
// src/components/Counter.js
import React, {useReducer} from 'react';
const initState = 0;
const reducer = (state, action) => {
switch(action) {
case 'increment':
return state + 1;
case 'decrement':
return state - 1;
case 'reset':
return initState ;
default:
return state;
}
}
const Counter = () => {
const [currentState, dispatch] = useReducer(reducer, initState)
return (
<>
<h2>Count - {currentState}</h2>
<button onClick={() => dispatch('increment)}>Increment</button>
<button onClick={() => dispatch('decrement)}>Decrement</button>
<button onClick={() => dispatch('reset)}>Reset</button>
</>
)
}
export default Counter;
// src/index.js
import {render} eact-dom';
import Counter from './components/Counter'
render(<Counter />, document.getElementById('root'))
此外,initState与action还可以为object,这样可以管理多个state,以及赋予action额外的属性,比如每次递增递减多少
// src/components/Counter.js
import React, {useReducer} from 'react';
const initState = {
firstCount: 0,
secondCount: 10,
};
const reducer = (state, action) => {
switch(action.type) {
case 'increment':
return {...state, firstCount: state.firstCount + action.value}; // 需要合并
case 'decrement':
return {...state, firstCount: state.firstCount - action.value };
case 'increment2':
return {...state, secondCount: state.secondCount + action.value };
case 'decrement2':
return {...state, secondCount: state.secondCount - action.value };
case 'reset':
return initState ;
default:
return state;
}
}
const Counter = () => {
const [currentState, dispatch] = useReducer(reducer, initState)
return (
<>
<h2>FirstCount - {currentState.firstCount}</h2>
<button onClick={() => dispatch({type:'increment', value: 3})}>Increment 1</button>
<button onClick={() => dispatch({type:'decrement', value: 2})}>Decrement 1</button>
<h2>SecondCount - {currentState.secondCount}</h2>
<button onClick={() => dispatch({type:'increment2', value: 10})}>Increment 2</button>
<button onClick={() => dispatch({type:'decrement2', value: 5})}>Decrement 2</button>
<button onClick={() => dispatch({type:'reset'})}>Reset</button>
</>
)
}
export default Counter;
// src/index.js
import {render} eact-dom';
import Counter from './components/Counter'
render(<Counter />, document.getElementById('root'));
上述代码中reducer处有一些逻辑重复,可以使用声明多个useReducer来解决,并且声明的多个useReducer管理的状态是相互独立的;
// src/components/Counter.js
import React, {useReducer} from 'react';
const initStateOne = 0;
const initStateTwo = 10;
const reducer = (state, action) => {
switch(action.type) {
case 'increment':
return state + action.value
case 'decrement':
return state - action.value
case 'reset':
return initState ;
default:
return state;
}
}
const Counter = () => {
const [currentState, dispatch] = useReducer(reducer, initState.firstCount);
const [currentStatetwo, dispatchTwo] = useReducer(reducer, initState.secondCount); return (
<>
<h2>FirstCount - {currentState}</h2>
<button onClick={() => dispatch({type:'increment', value: 3})}>Increment 1</button>
<button onClick={() => dispatch({type:'decrement', value: 2})}>Decrement 1</button>
<button onClick={() => dispatch({type:'reset'})}>Reset</button> <h2>SecondCount - {currentStatetwo}</h2>
<button onClick={() => dispatchTwo({type:'increment', value: 10})}>Increment 2</button>
<button onClick={() => dispatchTwo({type:'decrement', value: 5})}>Decrement 2</button>
<button onClick={() => dispatchTwo({type:'reset'})}>Reset</button>
</>
)
}
export default Counter;
// src/index.js
import {render} eact-dom';
import Counter from './components/Counter'
render(<Counter />, document.getElementById('root'));
最后,useReducer对于状态的管理与useState一样,是处于组件级的,即Local state management; 如果需要组件之间共享状态管理,那么需要结合useContext来配合使用,方式为:
在需要共享状态的最近的共同的父组件元素上,使用useContext创建一个CustomContext,并定义reducer,initState,通过useReducer返回一对[state, dispatch],然后使用<CustomContext.Provider value={{state, dispatch}} ></CustomContext.Provider>传递到需要使用的子组件,然后在子组件通过 const context = useContext(CustomContext) 获取该值进行使用即可;