You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Store 中数据的更新通过 action 进行 dispatch,但 action 指示提供了 action_type 和 action_text,并没有去决定 Store 应该如何更新。
reducer 可以理解为 action 和 Store 进行关联的时候中间的一层,他接收 action_type 和 action_text,然后 switch action_type,在相关的条件下对相关的数据进行整合,最后结合原 Store 的 state 与 action 里面的 type/text 生成新的 state 给 Store,进行 Store 的更新。
4. Redux 工作状态机:
2.3 使用梗概
Redux is a predictable state container for JavaScript apps
Redux 只有一个单一的数据源,并且这个数据源是只读的,修改这个数据源必须通过 dispatch action,action 只是告知了 type 和 text,这个时候 reducer 结合上一个 state 和 action 做出自己的响应,返回新的 state 送入 store。
在 reducer 中,他接收上一个 state 与 action,返回一个新的 state。这个过程是纯函数式的,返回的结果由进去的参数决定,不会随着外界的变化而发生改变。
Redux 学习总结
1. 写在前面
对于复杂的 Web 交互应用,相继出现了一系列的 MV* 框架,09 年的 Angular 带动了一系列的发展。
在后期的开发过程中,大家发现 Angular 太过于重,双向绑定的数据流容易让数据变得不可控制。
React 的横空出世一度让 Web App 的概念如火如荼,这种单向的数据流也就需要新的模式来组织。
在这个过程中对状态的管理相继出现了 Flux 等解决方案,在后来的发展中,Redux 由于单一的 Store 让大家更是喜欢。
2. Just Do
2.1 抛开全家桶
React 开发和全家桶离不开关系,但全家桶极有可能阻碍我们对 Redux 的理解。
这里我们抛开全家桶,用 jsfiddle 来学习 Redux。
2.2 几个概念与一个状态机
1. store:
Redux 是用来管理 App 中状态的。 和 Flux 相比,Redux 最鲜明的特点就是只有一个 Store。那这个 Store 到底是用来干什么的?
很直观的, Store 就是用来储存整个应用的状态的,也就是 React 中的 state。
Store 除了储存整个应用的状态之外,还提供几个接口,包括: 组件获取状态的接口 getState()、组件通过 action 和数据进行 dispath 更新 Store 的接口 dispatch(action)、Store 发生改变之后进行 subscribe 改变组件 view 的接口 subscribe()。
2. action:
action,翻译过来就是
动作
的意思。他用来接受一个指示和数据,然后由 action 进行 dispatch 来根据这个动作和数据进行 Store 的更新。常见的action格式为如下,包括一个
type
和text
(可以为空):3. reducer:
Store 中数据的更新通过 action 进行 dispatch,但 action 指示提供了 action_type 和 action_text,并没有去决定 Store 应该如何更新。
reducer 可以理解为 action 和 Store 进行关联的时候中间的一层,他接收 action_type 和 action_text,然后 switch action_type,在相关的条件下对相关的数据进行整合,最后结合原 Store 的 state 与 action 里面的 type/text 生成新的 state 给 Store,进行 Store 的更新。
4. Redux 工作状态机:
2.3 使用梗概
Redux 只有一个单一的数据源,并且这个数据源是只读的,修改这个数据源必须通过 dispatch action,action 只是告知了 type 和 text,这个时候 reducer 结合上一个 state 和 action 做出自己的响应,返回新的 state 送入 store。
在 reducer 中,他接收上一个 state 与 action,返回一个新的 state。这个过程是纯函数式的,返回的结果由进去的参数决定,不会随着外界的变化而发生改变。
2.4 入门小例子
jsfiddle 见: https://jsfiddle.net/rccoder/shmxthbo/2/
上述的例子最后会出现结果:
如我们所愿,subscribe 监听 store 的变化得到上面的结果。
其中,createStore 接收的两个参数分别是 reducer 和 initState,为了让代码更加优雅,我们还可以把 initState 抽离出来:
再其次,在项目中为了项目的规范化,我们需要对所有的 action_type 常量进行统一的管理,放到单独的文件中,这样可以进一步的抽离:
2.5 小进阶
2.5.1 middleware
Redux 解决的正是状态的问题。在平时开发过程中,我们可能需要知道上一个状态以及现在的状态,以及发生这个改变的 action 与数据是什么。
这个时候就需要 middlerware 出厂了,middlerware 发生在 action 之后,reducer 之前,在 middlerware 中,我们调用 next(action) 函数就可以把 action 传递给 reducer。
middlerware 不仅仅能实现查看当前 action 与 action 旁边的两个状态,还能对特定的 action 最一些特定的处理,然后再传给 reducer。这也正是 middlerware 的本意。
我们在上面的代码上加上 middlerware,打印一下这个小程序的日志:
jsfiddle 见:https://jsfiddle.net/rccoder/shmxthbo/3/
结果如下:
可以说这个日志比较明显的反应了程序中状态的转移与转移条件。
加上 middlerware 之后整个 Redux 的运行状态转移图如下:
2.5.2 拆分 reducer
上面例子中 Store 的 State 是很简单的:
在真是环境中,state 往往是复杂的。对于 reducer 而言,我们也可能根据相应的业务需求拆分出不同的 reducer,这样就避免了在一个文件里面写出一堆的 case。
对于下面的 Store
我们可以拆分为两个 reducer
如此, reducer 不再负责整个 reducer,而是把它下分到 reducerA 和 reducerB 两个 reducer, 每个 reducer 互相独立。
这种做法是非常值得推荐的,尤其是在大型应用中, Redux 官方也给出了合并 reducer 的 API:
结合上面的描述,对贯穿整个的例子做一个修改:
jsfiddle 见 https://jsfiddle.net/rccoder/shmxthbo/5/
2.5.3 Redux 异步
我们需要保持 reducer 是函数式的,这也就意味着在 reducer 中相同的输入一定有相同的返回,并且这个返回时及时的。
在应用开发中,我们经常会遇到一些异步的请求,这个需要显然是存在的一个问题。
通常的,我们有下面的几个解决方案:
2.5.3.1 理所当然
对于异步这种情况理所当然我们有着这样一种想法:在异步得到结果之后进行 dispatch。
在简单场景下,这种做法是完全接受的。但是当异步比较多比较复杂的时候,他的缺点也就暴露了出来:
2.5.3.2 middleware 上做文章
前面在介绍 middleware 的时候,提到 middleware 是介于 Action 与 Reducer 之间的,所以当 action 经过 middleware 的时候,完全由 middleware 控制。
在 middleware 上做文章显然比理所当然那种方法好很多,我们可以封装相应的 middleware,然后做出不同的处理,把异步封装在 middleware 中。
无疑,在 middleware 上做文章是优雅的。
2.5.3.3 第三方组件
redux 本身不提供异步,不代表第三方也不支持,有下面的一些 thunk 能方便我们在 redux 中进行异步操作。
2.5.3.3.1 redux-thunk
redux-thunk 是 redux 官方钦定的异步组件,实质是 redux 的一个 middleware。
正如官方的介绍,redux-thunk 的目的就是让同步操作与异步操作以同一种方式来 dispatch:
如上,同样的 API 去实现异步操作。
如上,redux-thunk 判断 store.dispatch 传递进来的参数,如果是一个 thunk(延时函数),就处理 thunk 里面的东西,完事之后执行这个函数。
纵观 redux-thunk 的源码,也能感叹设计之美:
在实际操作中,我们可能需要标记异步是否实现完毕,一般情况下我们可以设置两个 Action 来标记:
2.5.3.3.2 其他
比较著名的 redux 异步组件还有 redux-premise、redux-saga 等,大家可以自行研究(我还没使用过😂)
2.5.4 Action Creater
尤其是在有异步操作的时候,比如我们 dispatch(thunk) 的时候,这个 thunk 是比叫大的,理论上我们需要对他封装一下:
我们发现,又可以优雅的 dispatch 了。 ✿
2.5.5 immutable
我们知道 Redux 的风格是函数式的,在函数式编程中经常会出现一个重要的概念: immutable。
在 Redux 中,Store 中的 state 应该就是 immutable 的,在上面的例子中,我们明显的看到每次不是修改 state, 而是返回一个新的 state。这个过程中,我们就希望 state 是 immutable 的。
在 JavaScript 中,没有这个特定。
immutable 要求的是值本身不被修改,这点也是和 const 的区别(“指针”不发生变化,比如用 const 声明一个 Object 之后,我们还能在给这个 Object 添加新的 key-value 对);最需要注意的是在 JavaScript 中引用类型相关(Object、Array)的变量。例如:
在上面的例子中,我们会发现 a 不会随着 b 的改变而发生变化,而 c 会随着 d 的改变发生变化。显然这个是不符合 immutable 的!
对于这个问题,我们可以使用一些没有副作用的方法来解决,比如对 Array 使用 concat 生成新的数组、对 Object 使用解构等
在实际开发过程中,我们可能会觉得像上面一样做可能容易犯错误,更重要的一点是直观地,我们会感觉到如果数据是 immutable 的,性能应该会更好,当然事实上也是如此。针对这个问题,我们可以使用一些库然后利用他的 API 来操作数据去保证数据是 immutable 的。
比较著名的一些 immutable 库有:
2.6 与 React 合作 —— react-redux
redux 是一个处理状态的库,尽管你听他的时候他经常和 react 出现,但这并不意味着 redux 只能和 react 一起用。他还可以和 Angular、backbone 等使用,甚至可以直接使用 redux,就和上面的描述一样。
严格来说他们是互相分离的,中间使用官方的 react-redux 就可以完美的把 redux 与 react 结合起来。
2.6.1 provider
Provider 是在原有的 APP 上面包一层,然后接收 store 作为 props,然后给 connect 用
2.6.2 connect
connect 应该是 react-redux 的核心。他接收 store 提供的 state 和 action,返回给我们的 react 组件;还有一个很重要的一点是在 connect 这层 react-redux 做了优化,保证给组件只传和他相关的 state,这也就保证了性能上的优势
2.6.3 实战
HTML:
JavaScript:
系列文章
The text was updated successfully, but these errors were encountered: