3、React之useReducer

146 阅读2分钟

useRecuceruseState一样,都是React hooks中引入用于状态管理的,更具体点,useState是利用useReducer来实现的。

       使用useReducer很简单,只需要 :

      1)  引入 useReducer: import {useReducer} from 'react'

      2)定义initState状态与reducer函数;其中reducer函数包含currentStateaction两               个参数,并根据action,返回新的状态;

      3)使用 useReducer(reducer, initState, init),返回当前状态currentState和一个执行相应actiondispatch;

       按照以上步骤,使用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'))

此外,initStateaction还可以为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,并定义reducerinitState,通过useReducer返回一对[state, dispatch],然后使用<CustomContext.Provider  value={{state, dispatch}} ></CustomContext.Provider>传递到需要使用的子组件,然后在子组件通过 const context = useContext(CustomContext) 获取该值进行使用即可;