redux是公共状态管理方案 官网
概念
store
下面是store打印结果:
store内的方法
具体详细的store方法可以看官网
dispatch
更新 state 的唯一方法是调用 store.dispatch()
并传入一个 action 对象
getState
store 将执行所有 reducer 函数并计算出更新后的 state,调用 getState()
可以获取新 state。
let { count } = store.getState()
subscribe
每当 dispatch action 的时候就会执行,state 树中的一部分可能已经变化。你可以在回调函数里调用 getState() 来拿到当前 state。
store.subscribe(() => {
console.log("subscribe", store.getState())
})
action
将 action 视为描述应用程序中发生了什么的事件.
type: 字符串,给这个 action 一个描述性的名字,比如"todos/todoAdded"
。我们通常把那个类型的字符串写成“域/事件名称”,其中第一部分是这个 action 所属的特征或类别,第二部分是发生的具体事情。
action 对象可以有其他字段,其中包含有关发生的事情的附加信息。按照惯例,我们将该信息放在名为 payload
的字段中。
const addTodoAction = {
type: 'todos/todoAdded',
payload: 'Buy milk'
}
reducer
reducer 是一个函数,接收当前的 state
和一个 action
对象,必要时决定如何更新状态,并返回新状态。函数签名是:(state, action) => newState
。 你可以将 reducer 视为一个事件监听器,它根据接收到的 action(事件)类型处理事件。
const reducer = function reducer(state = initial, action) {
state = { ...state };
switch (action.type) {
case 'increase':
state.count++;
break;
default:
}
// return的内容,会整体替换STORE容器中的状态信息
return state;
};
运行流程
第一步 创建全局公共的答器 用来存储各组件需要的公共信息
const store = createStore(reducer);
第二步 在组件内部获取公共状态信息,然后渲染
let { count } = store.getState()
第三步 监听组件内公共状态的变化,将方法放入公共容器的事件池内
store.subscribe(函数)
第四步 创建 reducer,就上面写到的
第五步 派发任务,通知reducer执行修改的状态
store.dispatch({
type: 'increase'
});
这里先将store传入,然后获取,这里通过的是上下文React.createContext()
传递数据[store]
上下文传值具体在 React 父子、跨层级 组件通信了解及使用补充了,具体可以查看
redux在运行时会在内部进行一次派发,获取数据默认值
全量代码
目录结构
这里的 ThemeContext 是借助 上下文传递store
代码:
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
// antd汉化
import { ConfigProvider } from 'antd'
import zhCN from 'antd/locale/zh_CN';
import Demo from './views/test-redux/Demo';
import ThemeContext from './ThemeContext';
import store from './store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<>
<ConfigProvider locale={zhCN}>
<ThemeContext.Provider value={{ store }}>
<Demo />
</ThemeContext.Provider>
</ConfigProvider>
</>
);
ThemeContext.js
import React from "react";
const ThemeContext = React.createContext();
export default ThemeContext;
store/index.js
import { legacy_createStore as createStore } from 'redux';
let initial = {
count: 0
};
const reducer = function reducer(state = initial, action) {
console.log("action", action);
state = { ...state };
switch (action.type) {
case 'increase':
state.count++;
break;
case 'decrease':
state.count--;
break;
default:
}
// return的内容,会整体替换STORE容器中的状态信息
return state;
};
/* 创建STORE公共容器 */
const store = createStore(reducer);
export default store;
test-redux/Demo.jsx
import React, { useContext, useEffect, useState } from 'react'
import DemoMain from './DemoMain';
import DemoChange from './DemoChange';
import ThemeContext from '../../ThemeContext';
export default function Demo() {
const { store } = useContext(ThemeContext)
let { count } = store.getState()
// 组件更新操作
const [_, setNum] = useState(0)
useEffect(() => {
store.subscribe(() => {
setNum(new Date())
})
}, [])
return (
<div>
<div>总计:{count}</div>
<DemoMain />
<DemoChange />
</div>
)
}
test-redux/DemoMain.jsx
import React, { Component } from 'react'
import ThemeContext from '../../ThemeContext'
export default class DemoMain extends Component {
static contextType = ThemeContext;
componentDidMount() {
// 组件更新
let { store } = this.context
store.subscribe(() => {
this.forceUpdate()
})
}
render() {
let { store } = this.context
let { count } = store.getState();
return (
<div style={{ margin: '20px 0' }}>
展示内容:{count}
</div>
)
}
}
test-redux/DemoChange.jsx
import React, { Component, useContext } from 'react'
import { Button } from 'antd'
import ThemeContext from '../../ThemeContext';
export default function DemoChange() {
let { store } = useContext(ThemeContext)
return (
<div>
<Button type="primary" onClick={() => {
store.dispatch({
type: 'increase'
});
}}>增加</Button>
<Button type="primary" onClick={() => {
store.dispatch({
type: 'decrease'
});
}}>减少</Button>
</div>
)
// }
}
运行结果:
点击增加,数字加1
但是这里可以看到,加在 reducer 内的action在初始化的时候被派发了一次,说明页面在第一次加载的情况下,dispatch派发了此次给state赋初始值
redux为什么不能直接修改状态值?
官方给的是 如果想改变状态state(不能直接改),需要使用store提供的dispatch方法,去派发一个action(动作)。这个动作由Aaction Creators来创建一个对象,将动作派发出去,通知这个store进行修改,store修改不是自己进行修改,是通过Reducers进行状态改变,在Reducers改变状态以后,要通知store,因为store内可能会挂载特别的订阅,这里的订阅会通知组件去做更新。这个就是一个完整的单向数据流。
原因:
如果直接修改,公共状态的变量都分布在各个组件了,不利于维护、管理和逻辑复用 ,而且状态不利于追踪修改位置。