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> }