Redux
作用
集中式管理 react、vue、angular 等应用中多个组件的状态,是一个库,不单单可用于 react,只是更多的用于 react 中
模型图
三个核心
action
- 作用:action 是把数据从应用传到 store 的有效载荷,是 store 数据的唯一来源
- 创建
javascript
import { INCREMENT, DECREMENT } from "./constant";
export const incrementAction = (data) => {
return { type: INCREMENT, data };
};
export const decrementAction = (data) => {
return { type: DECREMENT, data };
};
- 页面上的使用:通过分发 action 操作数据
javascript
import { incrementAction, decrementAction } from "./redux/actions";
export default class index extends Component {
increment = () => {
const { value } = this.selectNumber;
store.dispatch(incrementAction(value));
};
}
- 异步 action:同步 action 中返回值为对象,而异步 action 中返回值为函数,其中一般会调用同步 action
javascript
export const incrementAsyncAction = (data, delay) => {
return (dispatch) => {
setTimeout(() => {
dispatch(incrementAction(data));
}, delay);
};
};
reducer
- 作用:reducer 指定了应用状态的变化如何响应 action 并发送到 store 中
- 特征:本质是一个纯函数,接收两个参数,之前的状态(preState)、动作对象(action)。第一次被调用时,preState 为 undefined
- 创建
javascript
import { ADD_PERSON } from "../constant";
export default function personReducer(preState, action) {
if (preState === undefined) {
preState = [
{
id: "001",
name: "Tom",
age: 23,
},
];
}
// 从action中取出type和data
const { type, data } = action;
switch (type) {
case ADD_PERSON:
// 没有对preState进行push或unshift操作,因为redux默认若返回值和之前状态一致,则不更新页面
return [data, ...preState];
default:
return preState;
}
}
- 纯函数 只要是同样的输入,必定得到同样的输出。遵循以下约束
- 不得改写参数
- 不能调用 I/O 的 API
- 不能调用 Date.new()或者 Math.random()等不纯的方法,因为每次会得到不一样的结果
store
作用:将 action 和 reducer 联系在一起,维持应用中的状态
特征:一个应用只有一个 store。当需要拆分数据处理逻辑时,应该使用多个 reducer
创建
javascriptimport { legacy_createStore } from "redux"; import countReducer from "./reducer"; export default legacy_createStore(countReducer);
当使用异步 action 后,需对 store 进行修改,使用 redux-thunk 和中间件支持异步 action,修改后的 store 文件如下:
javascriptimport { legacy_createStore, applyMiddleware } from "redux"; // 用于支持异步action import thunk from "redux-thunk"; import countReducer from "./reducer"; export default legacy_createStore(countReducer, applyMiddleware(thunk));
页面上取值:
javascript
render() {
return (
<div>
<h1>当前求和为{store.getState()}</h1>
</div>
)
}
react-redux
定义
react-redux 其实是 Redux 的官方 React 绑定库,其中封装了一些 Redux 与 React 连接的操作,可以是 Redux 的使用更加简单
模型图
规则
- 所有的 UI 组件被一个容器组件包裹,它们是父子关系
- UI 组件不与 Redux 进行操作,而是由容器组件与 Redux 进行操作,可以使用 Redux 的任意 api
- 容器组件会传给 UI 组件如下数据:
- 状态,即 mapStateToProps()
- 操作状态的方法,即 mapDispatchToProps()
基础使用(见 04-react-redux 基础使用)
建立容器组件时的注意点
- 容器组件与 UI 组件通过 react-redux 中的 connect 进行连接,传递 mapStateToProps 和 mapDispatchToProps
- mapStateToProps()
- 用于传递状态
- 返回一个对象
- react-redux 在调用该函数时已经传入了 state
- 此处的值传入 UI 组件中,UI 组件可使用 this.props.xxx 拿到对应的值
- 用到的 store 在根目录中通过 Provider 包裹 App 组件并传入 store 的方式获取javascript
const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode> );
- mapDispatchToProps()
- 用于传递操作状态的方法
- 返回一个对象,对象的 key 自定义,value 是一个方法
- 注意简写方式
建立 UI 组件时的注意点
- 不直接参与 Redux 的使用
- 使用 this.props.xxx 拿到容器组件传来对应的值
融合 UI 组件与容器组件
开发时将 UI 组件与容器组件进行融合后放到一个文件中(见,05-融合 UI 组件与容器组件)
多个组件间的数据共享(重要,见 06-react-redux 数据共享)
- 完善各个组件的 action 和 reducer
- 合并 reducer,如下
javascript
import { combineReducers } from "redux";
import countReducer from "./reducers/count";
import personReducer from "./reducers/person";
/**
* 合并Reducer
* 使用combineReducers合并Reducer,key为自定义,value为reducer
*/
export default allReducer = combineReducers({
count: countReducer,
persons: personReducer,
});
注意:合并 reducer 后导致 state 变化,变为一个新的对象,对于组件 mapStateToProps 中对应的 state 需要通过.属性
的方式取到 3. 修改 store,使用合并后的 reducer
javascript
import { legacy_createStore, applyMiddleware } from "redux";
// 用于支持异步action
import thunk from "redux-thunk";
// 合并后的reducer
import allReducer from "./reducers/index";
export default legacy_createStore(allReducer, applyMiddleware(thunk));