前言
上一篇介绍了 react-router,今天介绍 redux。
正文
什么是 Redux?
现如今,我们的项目都是由一个一个的模块组成的,组件化的思想更适合大且复杂的项目。
在此之前,React 并不适合写大型应用,因为它当时还没有很好地解决组件之间的通信问题。
为了解决这个问题,2014 年 Facebook 提出了 Flux 架构的概念,引发了很多的实现。2015 年,Redux 出现,将 Flux 与函数式编程结合在一起,很短时间内就成为了最热门的前端框架。
什么时候需要 Redux?
有人说过,挺有道理的哈。
如果你不知道是否需要 Redux,那就是不需要它。
在以下场景你可以考虑使用它:
- 组件间需要共享状态
- 状态需要在任何地方都能拿到
- 一个组件需要改变另一个组件的状态
- 一个组件需要改变全局状态
*以上内容引自阮一峰老师的博客,本教程是为了接入而接入,哈哈。
Redux 设计思想
- Web 应用是一个状态机,View 与 State 是一一对应的。
- 所有的状态,保存在一个对象里面。
基本概念和 API
先了解一下以下几个概念吧
- Store:保存数据的容器。由
Redux
提供的createStore
函数来生成唯一的Store
对象。 - State:
Store
对象包含的数据。当前的状态,可通过store.getState()
获取。Redux 规定一个State
对应一个View
。 - Action:
View
发出的动作(如用户点击鼠标等行为)通知State
要发生改变。Action
是改变State
的唯一办法。它是一个对象,其中type
属性是必须的,表示Action
的名称,其他属性可以自由设置,其社区有一个规范可以参考。如const action = { type: 'SOMETHING_TODO', payload: 'SOME DATA' }
。 - Action Creator:生成
Action
的函数。当有若干Action
时,全部手写可能略显麻烦,可以定义一个函数来生成Action
,这种函数叫做Action Creator
。 - store.dispatch():是
View
发出Action
的唯一方式。 - Reducer:当
Store
收到Action
之后,必须返回一个新的State
,这样View
才会发生变化,这种State
的计算过程叫做Reducer
。它是一个纯函数。 - Pure Function:即纯函数,同样的输入,必定得到同样的输出,且没有任何副作用
- store.subscribe():监听
State
的变化,一旦State
发生变化,就自动执行这个函数。它返回一个函数,执行该返回函数就解除监听。
实现最简单的 Store 案例
先安装 redux
依赖。
$ yarn add redux@4.0.4
在 src/js/store
目录下新建一个 index.js
文件。
// store/index.js import { createStore } from 'redux' // Reducer 处理函数 const reducer = (prevState, action) => { const { type, payload } = action switch (type) { case 'ADD': // 一定要不能修改 state,而是返回一个新的副本 // 倘若 state 是引用数据类型,一定要借助 Object.assign、对象展开运算符(...)、其他库的拷贝方法或者自己实现深拷贝方法,返回一个新副本 return prevState + payload case 'SUB': return prevState - payload default: // default 或者未知 action 时,返回旧的 state return prevState } } // 初始值 const initialState = 0 // 创建 Store(也可以不传入 initialState 参数,而将 reducer 中的 state 设置一个初始值) const store = createStore(reducer, initialState) // 监听 state 变化 // const unsubscribe = store.subscribe(() => { // console.log('监听 state 变化', store.getState()) // }) // 解除监听 // unsubscribe() export default store
我们在 Home 组件引入 Store,并修改成:
// pages/home/index.js import React, { Component } from 'react' import store from '../../store' class Home extends Component { constructor(props) { super(props) this.state = {} } // Action Creator 函数 actionCreator(type, payload) { return { type, payload } } handle(type, val) { // 创建 Action const action = this.actionCreator(type, val) // 派发 Action store.dispatch(action) // 获取 State 快照 console.log(`当前操作是 ${type},State 为:${store.getState()}`) } render() { return ( <div> <h3>Home Component!</h3> <button onClick={this.handle.bind(this, 'ADD', 1)}>加一</button> <button onClick={this.handle.bind(this, 'SUB', 1)}>减一</button> </div> ) } } export default Home
上面案例,我们做了一个很简单的加减操作。
通过 redux
提供的 createStore
函数创建了唯一的一个 store
对象,该函数接收三个参数 createStore(reducer, [preloadedState], enhancer)
,其中第一第二个分别是 reducer
函数和初始值,第三个一般是使用中间件时用到,我们后面会用到,这里暂不展开探讨。(点这里了解更多)
Reducer
函数接收两个参数 reducer(state, action)
,分别是 previousState(旧状态) 和 Action。在首次执行 state
为 undefined
,可以为它设置一个初始值,或者在 createStore
中传入。它有点类似 Array.prototype.reduce()。
借助我们在 Home
组件下引入 store
,并添加两个按钮,对 store
的 state
做加减操作。
至此
我们最简单 redux 案例实现了,但是这个距离我们想要的,还不够哦。
在此抛出几个问题:
- 如何接入我们的 Component 了,当 state 发生变化时,使其自动更新 View?
- 组件如何共享 Store?
- 如何查看 State 的变化?