Redux
资料
- react-redux流程与实现分析
- 《看漫画,学 Redux》 —— A cartoon intro to Redux
- Redux 中文网
- React 实践心得:react-redux 之 connect 方法详解
- 解读redux工作原理
React 是构建 UI 的库,只是 DOM 的一个抽象层,并不是 Web 应用的完整解决方案。
有两个方面,它没涉及
1 代码结构
2 组件之间的通信
对于大型的复杂应用来说,这两方面恰恰是最关键的。因此,只用 React 没法写大型应用。
Redux 概述
Redux 是 JavaScript 应用的可预测状态容器,用来集中管理状态。(A predictable state container for Javascript apps)
特点:集中管理、可预测、易于测试、易于调试、强大的中间件机制满足你所有需求。
注意
:redux 是一个独立于 react 的库,可以配合任何 UI 库/框架来使用。
注意
:如果你还不知道是否需要使用 Redux,那就是不需要它。
yarn add redux
三个核心概念
action
动作,用来描述要执行的动作- 比如:计数器案例中的 +1 就是一个动作
- 比如:登录功能中,登录就是一个动作
- 可以比喻成“砖” 家,仅仅是提出想法
reducer
接收到 action ,并且来执行这个动作- 实际的执行者,可以看做是 “搬砖的”
store
是 action 和 reducer 的桥梁,将 action 传递给 reducer ,由 reducer 来完成整个动作- 比喻成 “管理则”
整个过程: 管理者(store) 将 专家提出来的想法(action) 传递给 搬砖的人(reducer),最终,由reducer完成了这个任务(动作)。
action
action 用来描述要执行的动作(功能)
action 实际上就是普通的JS对象
约定1
:必须提供 type
属性,type 属性用来描述当前动作的类型
约定2
:type 属性的值是一个字符串,任务类型使用纯大写字母来表示,多个单词之间使用 _ 分割
约定3
:可以携带完成该动作需要的其他数据,这些数据(属性名)是可以任意名称的
// action
// 添加任务的动作
{
type : 'ADD_TODO' }
// 因为为了完成添加任务的动作,需要一个任务名称,所以,动作中可以携带完成该动作需要的数据
{
type: 'ADD_TODO', name: '吃饭' }
// 删除任务的动作
{
type: 'DELETE_TODO', id: 3 }
reducer
reducer 使用来完成 action 的
reducer 实际上就是一个普通的JS函数
该函数能够接受两个参数: (state, action ) => newState
作用:根据 旧状态 和 action(动作) ,来计算出新的状态
注意
:reducer 一定要有返回值!
注意
:在reducer 中不要直接修改 state,应该创建新的 state (状态不可变原则)
注意
:reducer 应该是一个纯函数(同样的输入,必定得到同样的输出),不要有修改参数、调用 Math.random() 等不纯的操作。
// action => { type: 'ADD_TODO', name: '吃饭' }
// 假设 state => [{}, {}]
const reducer = (state, action) => {
switch(action.type) {
case 'ADD_TODO':
// 1 执行 添加任务 的逻辑代码
// state.push() 不要这么做!!!
// 2 返回 添加任务 后的新状态
return [...state, {
name: action.name }]
case 'DELETE_TODO':
// 1 执行 删除任务 的逻辑代码
// 2 返回 删除任务 后的新状态
return state.filter(item => item.id !== action.id)
default:
// 如果当前 reducer 遇到无法处理的 action,就会执行 default
// 此时,应该直接返回 state
return state
}
}
store
注意
:一个 redux 应用中只有一个 store (仓库)
作用:将 action 和 reducer 组合在一起
职责:
- 提供整个应用的 state
- 提供 dispatch 方法,用来触发 action
- 提供 getState 方法,用来获取整个应用的 state
- 提供 subscribe 方法,监听 state 变化。
import {
createStore } from 'redux'
// 将 reducer 作为参数传递给 store,那么,store 中就可以拿到 reducer
const store = createStore( reducer )
// 通过 store 中的 dispatch 分发任务
// dispatch 的参数:就是 action (动作)
store.dispatch( {
type: 'ADD_TODO', name: '睡觉' } )
// 获取状态:
const state = store.getState()
// 这个返回值,用来取消本次订阅,取消后,状态变化时,就不会再执行该回调函数了
const unsubscribe = store.subscribe(() => {
console.log('当前状态为:', store.getState())
})
// 取消订阅
unsubscribe()
redux 的执行过程
- 在创建 store 的时候,redux会自动触发一次 reducer,目的:为了得到初始状态
// 模拟 redux 内部初始化操作:
reducer(undefined, {
type: '@@redux/INITx.n.f.s.j.5' })
function reducer(state = 0, action) {
// state 此时为默认值: 0 (因为第一次 redux 传入的值为 undefined)
// action ==> { type: '@@redux/INITx.n.f.s.j.5' }
switch (action.type) {
case 'ADD':
return state + 1
default:
// 因为该 reducer 无法处理 redux 生成的随机 动作类型
// 所以,执行了此处的 default,也就是返回了 默认状态:0
return state
}
}