概述
https://www.bilibili.com/video/BV11r4y1n7Sj?p=1
Redux 是 JavaScript 应用的状态容器,提供可预测的状态管理。
使用场景
- 你有很多数据随时间而变化
- 希望状态有一个唯一确定的来源
- 所有状态放在顶层组件中管理不可维护
功能特点
- 集中式的存储和管理应用的状态
- 处理组件通讯问题时,无视组件之间的层级关系
为什么 React 要使用 Redux
React 是 DOM 的一个抽象层(UI 库),并不是 Web 应用的完整解决方案,因此 React 在涉及到数据的处理以及组件之间的通信时比较复杂。对于大型的复杂应用来说,这两方面十分关键,因此只用 React 写大型应用比较吃力。
安装 Redux
npm i redux
核心概念
https://www.bilibili.com/video/BV11r4y1n7Sj?p=3
action
描述了有事情发生这一事实,并没有描述应用如何更新 state。一个 js 对象,
包含两个属性:
- 第一个 type 属性必填,值为字符串
- 第二个属性可选,表示本次动作携带的数据,第二个属性名称可自定义
特点:
- 只描述做什么
- JS 对象,必须带有 type 属性,用于区分动作的类型
- 根据功能的不同,可以携带额外的数据,配合该数据来完成相应功能
const action = {
type: "add"
payload: 3
}
reducer
一个函数,根据传入的旧状态和 action,返回新的状态
const initState = 0
const reducer = (previousState = initState, action) => {
switch (action.type) {
case 'add':
return previousState + 1
case 'addN':
return previousState + action.payload
default:
return previousState
}
}
store
存储状态的仓库,整合 action 和 reducer。是 Redux 的核心
特点:
- 一个应用只有一个 store
- 维护应用的状态,获取状态: store.getState()
- 创建 store 时接收 reducer 作为参考: const store = createStore(reducer)
- 发起状态更新时,需要分发 action: store.dispatch(action)
其他 API
- 订阅(监听)状态变化: const unSubscribe = store.subscribe(() => {})
- 取消订阅状态变化: unSubscribe()
import { createStore } from 'redux'
const store = createStore(reducer)
// 数据改变后的回调函数
store.subscribe(() => {
...
})
// 修改状态
store.dispatch(action)
执行过程
获取默认值
- 只要创建 store,Redux 就会调用一次 reducer,且 type 是一个随机值,这次调用 reducer 的目的是获取状态的默认值,这个初始值将成为下一次调用 store.getState() 方法来获取 Redux 状态值的初始值
- type 是随机值确保了它不会被用户业务逻辑处理,而只能去匹配默认值
更新状态
- 当需要更新状态时,就先分发动作 store.dispatch(action)
- Redux 内部,store 就会调用 reducer,传入:上一次的状态和action,计算出新的状态并返回
- reducer 执行完毕后,将最新的状态交给 store,store 用最新的状态替换旧状态,状态更新完毕
React-redux
基本使用
- 安装react、redux与react-redux
- 按 redux 要求,创建好 store, reducer, action
- 从 react-redux 中引入 provider, useSelector, useDispatch 来操作 redux
npm i react-redux
Provider
直接包装在根组件上,这样就不需要在每个组件都引入 store 了
<Provider store={store}>
useSelector
获取公共状态,不再需要使用 store.getState() 获取状态,state变化了就会自动更新
const 状态 = useSelector(store的数据 => 需要的部分)
useDispatch
派发action,修改数据
const dispatch = useDispatch(), dispatch(action)
根组件的文件示范
https://www.bilibili.com/video/BV11r4y1n7Sj?p=9
// 主页面
import React from 'react'
import ReactDom from 'react-dom'
import App from './App'
import store from './store'
import { Provider } from 'react-redux'
ReactDom.render {
<Provider store={store}
<App />
</Provider>
document.getElementById('root')
}
// store
...
// 子页面
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
export default function Son() {
const dispatch = useDispatch()
const num = useSelector((state) => state)
return (
<div>
{ num }
<button onClick={() => {dispatch(type: 'add')}}></button>
</div>
)
}
Reducer的拆分与合并
https://www.bilibili.com/video/BV11r4y1n7Sj?p=12&vd_source=74
使用 combineReducers 函数对多个 Reducer 进行合并
import book from './book'
import user from './user'
import { combineReducers } from 'redux'
const rootReducer = combineReducers({
book,
user
})