React之Redux
简介
redux
统一保存数据,在隔离了数据与UI的同时,负责处理数据的绑定。
什么时候需要使用Redux
- 组件需要共享数据(状态state)的时候
- 某个状态需要在任何地方都可以被随时访问的时候
- 某个组件需要改变另一个组件的状态的时候
具体使用场景如:语言切换、黑暗模式切换、用户登录全局数据共享…
Redux架构
- redux是的诞生是为了给 React 应用提供「可预测化的状态管理」机制。
- Redux会将整个应用状态(其实也就是数据)存储到到一个地方,称为store
- 这个store里面保存一棵状态树(state tree)
- 组件改变state的唯一方法是通过调用store的dispatch方法,触发一个action,这个action被对应的reducer处理,于是state完成更新
- 组件可以派发(dispatch)行为(action)给store,而不是直接通知其它组件
- 其它组件可以通过订阅store中的状态(state)来刷新自己的视图
.
Redux工作流
自己画了个比较粗浅的流程图,可以结合实际发朋友圈的场景来理解:
- Store:是Redux中带有推送功能的数据仓库
- Reducer:是帮助Store处理(初始化、修改、删除)数据的方法
- Actions:是数据更新的指令,会告诉Reducer如何去处理数据
- Dispatch:是发送数据更新的指令(提交Actions)的过程
Redux三大原则
- 单一数据源
state
是只读的,修改state
唯一方法就是触发action
- 使用纯函数
reducer
来修改state
,返回一个新的state
给store
Redux简单流程
// redux三大块 store action reducer
import { createStore } from 'redux';
const initState = {
count: 0,
}
// 1、action用来修改store
const action1 = { type: 'INCREMENT' }
const action2 = { type: 'DECREMENT' }
const action3 = { type: 'ADDNUM', num: 10 }
const action4 = { type: 'REDUCENUM', num: 20 }
// 2、reducer是连接store和action,返回新的state给store
const reducer = (state = initState,action) => {
switch (action.type) {
case "INCREMENT": return {...state,count: state.count + 1}
case "DECREMENT": return {...state,count: state.count - 1}
case "ADDNUM": return {...state,count: state.count + action.num }
case "REDUCENUM": return {...state,count: state.count - action.num }
}
}
// 3、store保存状态,创建一个对象即可
const store = createStore(reducer);
// 5: 在派发之前监听store的变化
store.subscribe(() => {
console.log(`count:${store.getState().count}`);
})
// 4、派发action
store.dispatch(action1)
store.dispatch(action2)
store.dispatch(action3)
store.dispatch(action4)
Redux流程详解
在src下新建redux文件夹
1. Store
在redux文件夹下新建store.ts
import { createStore } from 'redux';
import reducer from './reducer';
const store = createStore(reducer); // createStore可以帮助我们创建一个store
export default store;
store就是redux的一个数据中心,简单的理解就是我们所有的数据都会存放在里面,然后在界面上使用时,从中取出对应的数据。因此最开始,我们要创建一个这样的store,redux提供了createStore方法。
2. Reducer
在redux文件夹下新建reducer.ts
import i18n from 'i18next';
const defaultState = {
language: 'zh',
languageList: [
{ name: '中文', code: 'zh' },
{ name: 'English', code: 'en' },
{ name: '新增语言', code: 'add' }
],
};
const reducer = (state = defaultState, action) => {
switch (action.type) {
case 'CHANGELANGUAGE': // 切换语言
i18n.changeLanguage(action.value);
return { ...state, language: action.value }; // 不能直接修改旧的state,而是返回一个新的state来替代
case 'ADDLANGUAGE': // 新增语言
return { ...state, languageList: [...state.languageList, action.value] };
default:
return state;
}
};
export default reducer;
Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。
3. Action
在redux文件夹下新建action.ts
export const changeLanguage = value => ({ type: 'CHANGELANGUAGE', value });
export const addLanguage = value => ({ type: 'ADDLANGUAGE', value });
Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。
4. 组件中使用
语言切换组件Language.tsx
import React from 'react';
import { withRouter } from 'react-router-dom';
import store from '../../redux/store';
import { changeLanguage, addLanguage } from '../../redux/action';
class LanguageComponents extends React.Component{
constructor(props) {
super(props);
const storeState = store.getState();
this.state = {
language: storeState.language,
languageList: storeState.languageList
}
// 订阅store store发生改变时,自动触发storeChange方法
store.subscribe(this.storeChange.bind(this));
}
storeChange() {
let storeState = store.getState(); // 得到当前state状态,包含所有store属性
this.setState({
language: storeState.language,
languageList: storeState.languageList
}); // 重新渲染 View
}
clickHandler = (e) => {
// 通过 store.dispatch() 将 action 传到 store
let val = e.key;
if (val == 'add') {
store.dispatch(addLanguage({ name: '新的语言', code: 'new_lang' }));
} else {
store.dispatch(changeLanguage(val));
}
}
render() {
return (
<div>
<Menu onClick={this.clickHandler}>
{this.state.languageList.map((item) => {
return <Menu.Item key={item.code}>{item.name}</Menu.Item>
})}
</Menu>
当前语言是{this.state.language === 'zh' ? '中文' : 'English'}
</div >
);
}
};
export const Language = withRouter(LanguageComponents);
store包含的方法:
store.dispatch
帮助我们派发action,这个action会传递给storestore.getState
获取到store里面所有的数据内容store.subscribe
可以让我们订阅(监听) store的改变 只要store发生改变, 这个方法的回调函数就会执行