P07:用useReducer实现Redux效果的小案例
在实际使用中,useContext
和useReducer
是可以实现类似Redux
的效果,并且一些简单的个人项目,完全可以用下面的方案代替 Redux,这种做法要比 Redux 简单一些。因为useContext
和useReducer
在我之前的文章中已经学习过了,所以我们把精力就放在如何模拟出Redux
的效果。如果你目前还没掌握基本的语法,可以再复习一下前面两篇文章的知识点。
理论上的可行性
我们先从理论层面看看替代Redux
的可能性,其实如果你对两个函数有所了解,只要我们巧妙的结合,这种替代方案是完全可行的。
useContext
:可访问全局状态,避免一层层的传递状态。这符合Redux
其中的一项规则,就是状态全局化,并能统一管理。useReducer
:通过 action 的传递,更新复杂逻辑的状态,主要是可以实现类似Redux
中的Reducer
部分,实现业务逻辑的可行性。
经过我们在理论上的分析是完全可行的,接下来我们就用一个简单实例来看一下具体的实现方法。那我们先实现useContext
部分(也就是状态共享),再继续实现useReducer
部分(控制业务逻辑)。
先看一下今天的案例效果:
编写基本 UI 组件
在/src
目录下新建一个文件夹example6
,有了文件夹后,在文件夹下面建立一个ShowArea.js
文件。代码如下:
import React from 'react'; function ShowArea(){ return (<div style={{color:'blue'}}>字体颜色为 blue</div>) } export default ShowArea
显示区域写完后,新建一个Buttons.js
文件,用来编写按钮,这个是两个按钮,一个蓝色一个黄色。先不写其他任何业务逻辑。
import React from 'react'; function Buttons(){ return ( <div> <button>蓝色</button> <button>黄色</button> </div> ) } export default Buttons
然后再编写一个组合他们的Example6.js
组件,引入两个新编写的组件ShowArea
和Buttons
,并用<div>
标签给包裹起来。
import React, { useReducer } from 'react'; import ShowArea from './ShowArea'; import Buttons from './Buttons'; function Example6(){ return ( <div> <ShowArea /> <Buttons /> </div> ) } export default Example6
这步做完,需要到/src
目录下的index.js
中引入一下Example6.js
文件,引入后 React 才能正确渲染出刚写的 UI 组件。
import React from 'react'; import ReactDOM from 'react-dom'; import Example from './Example6/Example6' ReactDOM.render(<Example />, document.getElementById('root'));
做完这步可以简单的预览一下 UI 效果,虽然很丑,但是只要能满足学习需求就可以了。我们虽然都是前端,但是在学习时没必要追求漂亮的页面,关键时把知识点弄明白。我们写这么多文件,也就是要为接下来的知识点服务,其实这些组件都是陪衬罢了。
编写颜色共享组件color.js
有了 UI 组件后,就可以写一些业务逻辑了,接下来我们先实现状态共享,这个就是利用useContext
。在example6
文件夹下建立一个Color.js
文件,然后写入下面的代码。
import React, { createContext } from 'react'; export const ColorContext = createContext({}) export const Color = props => { return ( <ColorContext.Provider value={{color:"red"}}> {props.children} </ColorContext.Provider> ) }
代码中引入了createContext
用来创建共享上下文ColorContext
组件,然后我们要用{props.children}
来显示对应的子组件。
有了这个组件后,我们就可以把Example6.js
进行改写,让她可以共享状态。
import React from 'react'; import ShowArea from './ShowArea'; import Buttons from './Buttons'; import { Color } from './color'; //引入 Color 组件 function Example6(){ return ( <div> <Color> <ShowArea /> <Buttons /> </Color> </div> ) } export default Example6
然后再改写showArea.js
文件,我们会引入useContext
和在color.js
中声明的ColorContext
,让组件可以接收全局变量。
import React , { useContext } from 'react'; import { ColorContext } from './color'; function ShowArea(){ const {color} = useContext(ColorContext) return (<div style={{color:color}}>字体颜色为{color}</div>) } export default ShowArea
这时候就通过useContext
实现了状态的共享,可以到浏览器中看一下效果。
上面我们用useContext
实现了 Redux 状态共享的能力,这节课看一下如何使用useReducer
来实现业务逻辑的控制。
在 color.js 中添加 Reducer
颜色(state)管理的代码我们都放在了color.js
中,所以在文件里添加一个 reducer,用于处理颜色更新的逻辑。先声明一个 reducer 的函数,它就是 JavaScript 中的普通函数,在讲useReducer
的时候已经详细讲过了。有了 reducer 后,在 Color 组件里使用useReducer
,这样 Color 组件就有了那个共享状态和处理业务逻辑的能力,跟以前使用的Redux
几乎一样了。之后修改一下共享状态。我们来看代码:
import React, { createContext,useReducer } from 'react'; export const ColorContext = createContext({}) export const UPDATE_COLOR = "UPDATE_COLOR" const reducer= (state,action)=>{ switch(action.type){ case UPDATE_COLOR: return action.color default: return state } } export const Color = props=>{ const [color,dispatch]=useReducer(reducer,'red') return ( <ColorContext.Provider value={{color,dispatch}}> {props.children} </ColorContext.Provider> ) }
注意,这时候我们共享出去的状态变成了 color 和 dispatch,如果不共享出去 dispatch,你是没办法完成按钮的相应事件的。
通过 dispatch 修改状态
目前程序已经有了处理共享状态的业务逻辑能力,接下来就可以在Buttons.js
使用dispatch
来完成按钮的相应操作了。先引入useContext
、ColorContext
和UPDATE_COLOR
,然后写onClick
事件就可以了。代码如下:
import React ,{useContext} from 'react'; import {ColorContext,UPDATE_COLOR} from './color' function Buttons(){ const { dispatch } = useContext(ColorContext) return ( <div> <button onClick={()=>{dispatch({type:UPDATE_COLOR,color:"blue"})}}>蓝色</button> <button onClick={()=>{dispatch({type:UPDATE_COLOR,color:"yellow"})}}>黄色</button> </div> ) } export default Buttons
这样代码就编写完成了,用useContext
和useReducer
实现了 Redux 的效果,这个代码编写过程比 Redux 要简单,但是也是有一定难度的。希望第一次接触的小伙伴能自己动手写 5 遍以上,把这种模式掌握好,因为在工作中经常用到。
码云笔记 » P07:用useReducer实现Redux效果的小案例