Redux 是 JavaScript 状态容器,提供可预测化的状态管理。类似vuex的全局存储状态。
Redux 由 Flux 演变而来,但受 Elm 的启发,避开了 Flux 的复杂性。 不管你有没有使用过它们,只需几分钟就能上手 Redux。
1.Redux 的三大原则:
- 单一数据源:整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中
- State 是只读的:唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象
- 使用纯函数来执行修改:为了描述 action 如何改变 state tree ,你需要编写 reducers
不使用redux,react兄弟组件传值图
2.Redux工作流向图
3.Action
它是 store 数据的唯一来源。你会通过 store.dispatch() 将 action 传到 store(Redux没经过处理的dispatch()方法只能同步更新state树中的数据). 定义一个Action类型
在组件中通过dispatch()调用创建函数
4.Reducer(纯函数)
Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生,state的更新只发生在Reducer且Reducer不会修改原来state的数据,而是生成新数据响应到store
注意永远不要在Reducer里面干这些事情:
- 不要修改state
- 在 default 情况下返回旧的 state。遇到未知的 action 时,一定要返回旧的 state。
- 执行有副作用的操作,如 API 请求和路由跳转;
- 调用非纯函数,如 Date.now() 或 Math.random()
为什么要这样呢?
纯函数概念 :
- 同的输入永远返回相同的输出
- 不修改函数的输入值
- 不依赖外部环境状态
- 无任何副作用
Redux通过比较新旧两个对象是否一致,这种较法,比较的是两个对象的存储位置,也就是浅比较法,所以,当我们 reducer 直接返回旧的 state 对象时,Redux 认为没有任何改变,从而导致页面没有更新。因为比较两个 javascript 对象中所有的属性是否完全相同,唯一的办法就是深比较,然而,深比较在真实的应用中代码是非常大的,非常耗性能的,需要比较的次数特别多,所以一个有效的解决方案就是做一个规定,当无论发生任何变化时,开发者都要返回一个新的对象,没有变化时,开发者返回旧的对象,这也就是 redux 为什么要把 reducer 设计成纯函数的原因
5.Store
Store 就是把action和reducer联系到一起的对象,Redux 应用只有一个单一的 store
- 维持应用的 state;
- 提供 getState() 方法获取 state;
- 提供 dispatch(action) 方法更新 state;
- 通过 subscribe(listener) 注册监听器;
- 通过 subscribe(listener) 返回的函数注销监听器
6.搭配React使用
Redux 和 React 之间没有关系。Redux 支持 React、Angular、Ember、jQuery 甚至纯 JavaScript。
安装React绑定库
npm install --save react-redux
7. Action异步处理数据
为确保Reducer不产生任何副作用,redux 把异步处理数据交给Action, 当初规定Action必须是一个纯对象,是出于实际需要。因为reducer必须是一个纯函数,这决定了dispatch的参数Action必须是一个带type字段的纯对象。现如今我们要加入异步请求,而中间件又可以中途拦截做一些处理,所以我们需要对函数式的Action做一些处理,引入Redux Thunk 中间件,Redux中间件的作用: 改造store.dispatch,解决异步操作
8.安装状态数据可视化工具redux-devtools
redux-devtools gitup地址 github.com/reduxjs/red…
rematch:
虽然现在写的项目封装过,导致差异很大。
因为@rematch/core 集成导致 参考:www.cnblogs.com/mengff/p/95…
rematch是对redux的二次封装,简化了redux是使用,极大的提高了开发体验。
1. rematch的优点
1.省略了action types不必再多次写字符串,使用model/method代替
2.省略了action creators直接调用方法,不必再生产action type,使用dispatch.model.method代替
3.省略了switch语句调用model.method方法,不必判断action type
4.集中书写状态,同步和异步方法在一个model中使用state,reducers和effects来写状态,同步和异步方法
2. rematch的model
model中直接写state,reducers,effects,十分集中方便
export const count = {
state: 0, // initial state
reducers: {
// handle state changes with pure functions
increment(state, payload) {
return state + payload
}
},
effects: (dispatch) => ({
// handle state changes with impure functions.
// use async/await for async actions
async incrementAsync(payload, rootState) {
await new Promise(resolve => setTimeout(resolve, 1000))
dispatch.count.increment(payload)
}
})
}
3. rematch的dispatch
dispatch可以直接调用同步和异步方法,不必再发送action
import { init } from '@rematch/core'
import * as models from './models'
const store = init({
models,
})
export const { dispatch } = store // state = { count: 0 }
// reducers
dispatch({ type: 'count/increment', payload: 1 }) // state = { count: 1 }
dispatch.count.increment(1) // state = { count: 2 }
// effects
dispatch({ type: 'count/incrementAsync', payload: 1 }) // state = { count: 3 } after delay
dispatch.count.incrementAsync(1) // state = { count: 4 } after delay
4. rematch的状态派发
依然使用redux的connect,mapStateToProps,mapStateToDispatch来派发状态和方法到子组件
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider, connect } from 'react-redux'
import store from './index'
const Count = props => (
<div>
The count is {props.count}
<button onClick={props.increment}>increment</button>
<button onClick={props.incrementAsync}>incrementAsync</button>
</div>
)
const mapState = state => ({
count: state.count
})
const mapDispatch = ({ count: { increment, incrementAsync }}) => ({
increment: () => increment(1),
incrementAsync: () => incrementAsync(1)
})
const CountContainer = connect(mapState, mapDispatch)(Count)
ReactDOM.render(
<Provider store={store}>
<CountContainer />
</Provider>,
document.getElementById('root')
)
疑问:state放在Redux Store上还是放在React上呢?
即需要去控制显示时,是通过内部state还是Redux的state去控制
-
- 这个state是否其他组件也会用得上?
- 这个state是否当组件被unmount然后再mount的时候还要存在
只有这两个问题的回答都是No的时候,才可以放在React中,否则放在Redux Store中