前言
- 细阅此文章大概需要 <math xmlns="http://www.w3.org/1998/Math/MathML"> 6 分钟 \color{red}{6分钟} </math>6分钟左右
- 本篇中讲述了:
- redux简述
- redux管理公共状态的基本流程
- 核心操作
- 派发过程
- 其他
- Redux使用详解
- 引入相关依赖
- 创建仓库
- 创建公共容器
- 跟组件基于上下文传递store
- 后代组件使用state
- 后代组件进行行为派发
- 欢迎在评论区探讨、留言,如果认为有任何错误都还请您不吝赐教,万分感谢。希望今后能和大家共同学习、进步。
- 下一篇会尽快更新,已经写好的文章也会在今后随着理解加深或者加入一些图解而断断续续的进行修改。
- 如果觉得这篇文章对您有帮助,还请点个赞支持一下,谢谢大家!
- 欢迎转载,注明出处即可。
redux简述
首先,我们都知道在react项目中通常用到的复合组件通信方案包括两大类:
- 父子组件之间的通信:
基于props属性进行通信
、基于Ref进行通信
- 祖先和后代通信:
通过Context上下文进行通信
除此之外,还有一种常见的实现组件信息共享、组件通信、全局公共状态管理的方案:redux/react-redux
。
接下来的几篇文章,我们就来学习一下redux
、redux工程化
、react-redux
、redux和react-redux部分源码的解读
以及redux中间件及处理机制
相关的内容。
redux管理公共状态的基本流程
核心操作
1. 创建一个全局公共容器: 用来存储各个组件需要的公共信息。这个容器包含两部分内容:
公共状态
:各个组件需要共享、通信的信息事件池
:(存放一些让组件可以更新的方法)
javascript
const store = createStore([reducer])
2. 在组件内部,获取最新的公共状态信息。
javascript
store.getState()
3. 创建一些可以让组件更新的方法,将其放到公共容器的事件池当中。
当公共状态一旦发生改变,就会默认立即通知事件池中的方法就会按照顺序依次执行,就会使对应的组件更新。组件只要更新,就可以从store容器中获取最新的状态进行渲染
subScribe
方法的返回值是一个方法,执行这个方法可以将刚才放入事件池中的方法移除掉。
javascript
let unsubscribe = store.subScribe(FUNC)
4. 创建公共容器的时候需要传递reducer
方法 ,它就相当于是一个管理员的角色,负责修改容器中的公共状态,并执行事件池中的方法。
当
reducer
方法执行时,会接收两个参数:
state
(容器中现有的公共状态,若没有则使用设置的默认值)action
(dispatch
执行时传入的行为对象,行为对象中必须包含type
属性(代表派发的行为标识),reducer
方法执行时会根据type
值的不同来修改不同的状态信息)
reducer
方法执行的返回值:return state
返回的信息将会替换store容器中的公共状态
tips:在reducer
中我们不能直接在过程中对state
进行修改,而是需要在return时
对state
进行整体替换,所以就需要我们在最开始把获取的state克隆一份
javascript
// 为reducer创建一个初始的状态值
const initState = {
a:100,
b:100
}
const reducer = function reducer(state=initState, action){
switch(action.type){
// ...根据传递的type不同,修改不同的状态信息
}
return state // 返回的信息将会替换store容器中所有的公共状态
}
5. 派发任务,通知reducer
方法执行,修改容器中的公共状态
我们不能直接修改容器中的状态,而是需要通过执行
store.dispatch(行为对象[OBJ])
派发任务,来通知reducer
方法执行来从而修改容器中的公共状态,并执行事件池中的方法,更新对应的组件。
javascript
store.dispatch({
type:xxx,
// ...
})
tips:想要找到reducer,就先去找store,然后找到对应的reducer,然后再根据行为标识,找到本次派发都执行了哪些逻辑,修改了哪些状态。
派发过程
- 第一次派发,实际上是在redux内部派发的,
state
没有值。 派发标识是一个随机生成的"乱码",不会和reduce中的任何一个逻辑匹配,最终会将自己设置的初始值赋给state
。
js
// 首次派发是redux进行初始化的内部派发
store.dispatch({
type:'随机生成的乱码,与我们reducer中的任何case都不匹配',
// ...
})
// 在reducer中最终return的是我们设置的初始state
// 此时state由undefined变为initState
- 第二次派发,实际上是给予我们自己的逻辑进行的第一次派发。
注意在进入switch前,克隆一份state,避免在过程中直接操作state,而是在return时对state进行整体替换
其他
除此之外,我们想要在组件当中用起来,还需要context
上下文的配合。
在根组件中创建上下文
,导入store
,将其传递到上下文
中,之后在我们需要用到store
的后代组件中,通过上下文
获取并进行使用即哪些
Redux使用示例
引入相关依赖
在package.json中引入redux
、react-redux
以及一些其他的中间件
创建仓库
一般来说,我们会在src
路径下创建一个store文件夹
,并在其中新建一个index.js文件
来创建公共容器,从而对公共状态进行管理
创建公共容器
javascript
// 创建公共容器
import {createStore} from 'redux'
// 为reducer创建一个初始的状态值
const initState = {
a:0,
b:0
}
/*管理员:修改store中的公共状态*/
const reducer = function reducer(state=initState, action){
// state: store中的公共状态(最开始没有时,为自己设置的初始值)
// action:dispatch执行时传入的行为对象,行为对象中必须包含type属性(代表派发的行为标识)
// 为了避免在过程中对`state`进行修改,而是需要在`return时`对`state`进行整体替换,所以就需要我们在最开始把获取的state克隆一份
state={...state}
switch(action.type){
// ...根据传递的type不同,修改不同的状态信息
case "adda":
state.a++
break;
case "addb":
state.b++
break;
default:
break;
}
return state // 返回的信息将会替换store容器中所有的公共状态
}
/*创建公共容器*/
const store = createStore(reducer)
export default store
根组件基于上下文传递store
js
// 在根节点引入store,基于上下文传递
import React from 'react';
import ReactDom from 'react-dom';
import App from './view/App';
/*引入redux公共容器*/
import store from './store';
/*引入上下文*/
import AppContext from './AppContext';
const root ReactDOM.createRoot(document.getElementById('root'))
root.rnder(
<AppContext.Provider value={{store}}> // 基于上下文传递公共容器
<App />
</AppContext.Provider>
)
后代组件使用state
js
/*引入上下文*/
import AppContext from './AppContext';
import Operator from './Operator';
const App = function () {
const {store} = useContext(AppContext) // 解构出我们的公共容器
const { a,b } = store.getState()// 获取组件中的公共状态
const [render, setRender] = useState(0);
const update = () => {
setRender(Math.random())
// 类组件可以直接基于this.forceUpdate()更新,操作更为方便
}
useEffect(()=>{
let unsubscribe = store.subscribe(update)
},[])
return <div>
<div>总数是:{a+b}</div>
<div>a总数是:{a}</div>
<div>b总数是:{b}</div>
<Operator />
</div>;
};
后代组件进行行为派发
js
/*引入上下文*/
import AppContext from './AppContext';
const Operator = function () {
const {store} = useContext(AppContext) // 解构出我们的公共容器
const handleAddA = () => {
store.dispatch({type:'adda'})
}
const handleAddB = () => {
store.dispatch({type:'addb'})
}
return <div>
<button onclick={handleAddA}>add a</button>
<button onclick={handleAddB}>add b</button>
// 点击按钮时派发任务,通知reducer执行,传递action【行为对象】,action中type为行为标识,在reducer中会找到对应的case并执行
</div>;
};
export default Operator