![2c369d2071c00d814bb703392d866e20.png](https://i-blog.csdnimg.cn/blog_migrate/a0a7dc3550c4a4b925b297b911d6e416.jpeg)
本文作者:开课吧木木
图文编辑:开三金
React的最后一篇基础课出来啦,前三节三金帮大家放到了专辑里,大家喜欢的可以去看哟。
![4250013ea8dc40cb8328ac96333ea1fc.png](https://i-blog.csdnimg.cn/blog_migrate/fd31106fdb520d3cd38fd11b018cc947.png)
Redux的核心概念
Redux 是一个独立的 JavaScript 状态管理库。曾经有人说过这样一句话。
"如果你不知道是否需要 Redux,那就是不需要它。"
Redux 的创造者 Dan Abramov 又补充了一句。
"只有遇到 React 实在解决不了的问题,你才需要 Redux 。"
首先,我们要理解 Redux 几个核心概念与它们之间的关系:
○store
○state
○action
○reducer
StoreStore就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个Store。
Redux提供createStore这个函数,用来生成Store:
![3c93c6dd3f0f3526448f8d6c71a778e5.png](https://i-blog.csdnimg.cn/blog_migrate/8b61c7c7bb36ca72697471dea298312f.png)
上面代码中,createStore函数接受另一个函数作为参数,返回新生成的 Store 对象。
stateStore对象包含所有数据。如果想得到某个时点的数据,就要对Store生成快照。
这种时点的数据集合,就叫做State。
当前时刻的State,可以通过store.getState()拿到:
![28e99e9e2e6d830d95451011041a74f8.png](https://i-blog.csdnimg.cn/blog_migrate/51c55668700f6b6b3b141068fd502365.png)
![d038eb3138de007d438523afe78ca9f8.png](https://i-blog.csdnimg.cn/blog_migrate/4d24338278154456ff7a97d64c224f96.png)
通过纯函数修改state
Redux 规定, 一个 State 对应一个 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么样,反之亦然。
state是只读的。
这里需要注意的是,为了保证数据状态的可维护和测试,不推荐直接修改state中的原数据。
什么是纯函数?
1、相同的输入永远返回相同的输出
2、不修改函数的输入值
3、不依赖外部环境状态
4、无任何副作用
使用纯函数的好处?
1、便于测试
2、有利重构
ActionState 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。
所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。
Action 是一个对象。其中的type属性是必须的,表示 Action 的名称。
其他属性可以自由设置:
![f84b466836fa3134379f7a288a3d77ee.png](https://i-blog.csdnimg.cn/blog_migrate/76ce928b15fcd409532a8fc23c11bf4a.png)
![289119e8460979c1fe472a8a2d221da4.png](https://i-blog.csdnimg.cn/blog_migrate/c70c6ec2656536646b887ffb07199785.png)
生成和使用Action
Action CreatorView 要发送多少种消息,就会有多少种 Action。
如果都手写,会很麻烦。
可以定义一个函数来生成 Action,这个函数就叫 Action Creator。
![42ee61775a8399e1f098917b5abd9876.png](https://i-blog.csdnimg.cn/blog_migrate/5486b68fe3d808661dcd55611cb9f34b.png)
store.dispatch()store.dispatch()是 View 发出 Action 的唯一方法。
![d3d22d790a23932bd761a11855ed8908.png](https://i-blog.csdnimg.cn/blog_migrate/c79656440b5993145efea1679ec2aaa1.png)
结合 Action Creator,这段代码可以改写如下。
store.dispatch(addTodo('LearnRedux'));
ReducerStore 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。
这种 State 的计算过程就叫做 Reducer。
Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State:
![c41efdd823988bba346aa57e14e855fc.png](https://i-blog.csdnimg.cn/blog_migrate/bfff6603ac16750b86564b2bf4602087.png)
整个应用的初始状态,可以作为 State 的默认值。
下面是一个实际的例子:
![8a0803548baac749798484d4cfa3d7cc.png](https://i-blog.csdnimg.cn/blog_migrate/35465ed4240418fd48c6b8b272768028.png)
store.subscribe()Store 允许使用store.su-bscribe方法设置监听函数。
一旦 State 发生变化,就自动执行这个函数。
![9094a2eada42c36ea9de5abe30a0b5d0.png](https://i-blog.csdnimg.cn/blog_migrate/6ea0dc89a397be1edcc1df2c4764f119.png)
显然,只要把 View 的更新函数(对于 React 项目,就是组件的render方法或setState方法)放入listen,就会实现 View 的自动渲染。
store.subscribe方法返回一个函数,调用这个函数就可以解除监听:
![3bf4c8d51d22abf51cd86f36e3da956f.png](https://i-blog.csdnimg.cn/blog_migrate/defce1ebe7dcc74d3a06f26399f69f2d.png)
![432dc8df86297f96d093cdb8767a3bb7.png](https://i-blog.csdnimg.cn/blog_migrate/e067a46846c3e03786a6f98361b0c429.png)
Reducer 的拆分
Reducer 函数负责生成 State。
由于整个应用只有一个 State 对象,包含所有数据,对于大型应用来说。
这个 State 必然十分庞大,导致 Reducer 函数也十分庞大。
请看下面的例子:
![1b43cf68d9f39851e453b9453e2116ca.png](https://i-blog.csdnimg.cn/blog_migrate/18b6b724d5ef54c91aed94f4df7b2033.png)
上面代码中,三种 Action 分别改变 State 的三个属性:
ADD_CHAT:chatLog属性
CHANGE_STATUS:statusMessage属性
CHANGE_USERNAME:userName属性这三个属性之间没有联系。
这提示我们可以把 Reducer 函数拆分。
不同的函数负责处理不同属性,最终把它们合并成一个大的 Reducer 即可。
![0d7c3de7bd61d22302c0fa34897f68f2.png](https://i-blog.csdnimg.cn/blog_migrate/56c35509ce011c2cf476c08f984ef5fc.png)
Redux 提供了一个combineReducers方法,用于 Reducer 的拆分。
你只要定义各个子 Reducer 函数,然后用这个方法,将它们合成一个大的 Reducer:
![d3d22d790a23932bd761a11855ed8908.png](https://i-blog.csdnimg.cn/blog_migrate/c79656440b5993145efea1679ec2aaa1.png)
这种写法有一个前提,就是 State 的属性名必须与子 Reducer 同名。
如果不同名,就要采用下面的写法:
![6fb1b06b663ed47a4dfc73e8554fa2ba.png](https://i-blog.csdnimg.cn/blog_migrate/cb321137fe864e0a962d92750d0d7e0f.png)
下面是combineReducer的简单实现。
![97f087ffecf69d892b0e7cdcee14ee34.png](https://i-blog.csdnimg.cn/blog_migrate/4a7427989bca5f84bdcc6e1df9457e90.png)
你可以把所有子 Reducer 放在一个文件里面,然后统一引入:
![0d7c3de7bd61d22302c0fa34897f68f2.png](https://i-blog.csdnimg.cn/blog_migrate/56c35509ce011c2cf476c08f984ef5fc.png)
工作流程
首先,用户发出 Action。
store.dispatch(action);
然后,Store 自动调用 Reducer,并且传入两个参数:
当前 State 和收到的 Action。
Reducer 会返回新的 State 。
![6fb1b06b663ed47a4dfc73e8554fa2ba.png](https://i-blog.csdnimg.cn/blog_migrate/cb321137fe864e0a962d92750d0d7e0f.png)
State 一旦有变化,Store 就会调用监听函数。
![a4825cbb7e6775660a3b656fdfe320cb.png](https://i-blog.csdnimg.cn/blog_migrate/4846e78fcd84821b9d0255b105f4b3b4.png)
listener可以通过store.getState()得到当前状态。
如果使用的是 React,这时可以触发重新渲染 View。
Provider 组件:
想在 React 中使用 Redux ,还需要通过 react-redux 提供的 Provider 容器组件把 store 注入到应用中
![08f46866217010da4850d5a0d07da4ab.png](https://i-blog.csdnimg.cn/blog_migrate/a60eae3edea1929f9d8b5c6acdc56d3c.png)
connect 方法:
有了 connect 方法,我们不需要通过 props 一层层的进行传递, 类似路由中的 withRouter
我们只需要在用到 store 的组件中,通过 react-redux 提供的 connect 方法。
把 store 注入到组件的 props 中就可以使用了
![7d61fc6aabcf74a464ad96b2081bc274.png](https://i-blog.csdnimg.cn/blog_migrate/5375732c5443154ff9005b35002fec5d.png)
注入 state 到 props
![79f0b8a86ea304a4ad16c164bf21856d.png](https://i-blog.csdnimg.cn/blog_migrate/645eb9f1f87bc1ee04fda05b65a04652.png)
connect 方法的第一个参数是一个函数
该函数的第一个参数就是 store 中的 state : store.getState()
该函数的返回值将被解构赋值给 props : this.props.items
redux-chunk
这是一个把同步 dispatch 变成异步 dispatch 的中间件。
安装:
![cb96e5f062237c96bb58760a6f53615c.png](https://i-blog.csdnimg.cn/blog_migrate/cf7082094b3665515ab76fedd4e222c7.png)
到这里,关于React的基础篇就全部更新完啦~
接下来我们会制作一系列关于【图形选择】的干货文章,非常适合需要夯实前端基础的同学!
对于前端基础较高的同学,我们也会为大家分享优质、深入的前端领域干货
还有非常实用的小道具推荐,还有每周五必更的【三金叨叨叨】
更多好文都在【开课吧前端团队】
再次感谢各位小伙伴的支持~
![0eeb18b92f65dd5a6526b348b081bfea.png](https://i-blog.csdnimg.cn/blog_migrate/e65e1028ea973376dcadbe87cf2e76e6.jpeg)
![b8850b44cdfa0e013f0e8a25e19c87ed.png](https://i-blog.csdnimg.cn/blog_migrate/5922625d9719fa9e97160409892395b7.jpeg)
![e8d83f5451c1e280127d343385616e46.png](https://i-blog.csdnimg.cn/blog_migrate/366474e13a8ed5f5a9ddc8e0a3d84c9b.jpeg)
![917f987277016ba3f55bbdf6f706f76e.png](https://i-blog.csdnimg.cn/blog_migrate/9f0da27a931e38dae04433c5a78db35a.jpeg)
你“在看”我吗?
![9eaad806e44aaca12e52414e309bb567.png](https://i-blog.csdnimg.cn/blog_migrate/81e32167f446abeb6c05820c32bf6c80.png)