Redux
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。
可以让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。
不仅于此,它还提供 超爽的开发体验,比如有一个时间旅行调试器可以编辑后实时预览。
Redux 除了和 React 一起用外,还支持其它界面库。 它体小精悍(只有2kB,包括依赖)。
- 英文原版:http://redux.js.org/
- Redux 中文文档: https://cn.redux.js.org/
- Redux 中文文档:https://www.redux.org.cn/
Redux Flow
三大原则
同步
官网地址:https://cn.redux.js.org/tutorials/essentials/part-1-overview-concepts
异步
官网地址:https://cn.redux.js.org/tutorials/essentials/part-5-async-logic
查看原图
react中使用redux
我们使用redux处理一个问题,点击按钮,实现左侧导航的展开与闭合,如下图:
查询文档,可知:点击按钮,修改Sider
容器的collapsed
属性为true
,即可满足要求。
但是,由于头部部分按钮和改Sider
容器不在一个组件,故此,就出现了兄弟组件的通信问题。
安装组件
安装 redux
和 react-redux
yarn add redux react-redux
创建redux文件夹及其他文件
创建的目录如下:
创建store
在redux文件夹下面,新建store.js用于创建store
import { createStore } from 'redux'
import { SidebarCollapsedReducers } from "./reducers/SidebarCollapsedReducers";
let store = createStore(SidebarCollapsedReducers)
我们在项目中,不可能只有一个Reducer。
随着应用变得越来越复杂,可以考虑将 reducer 函数 拆分成多个单独的函数,拆分后的每个函数负责独立管理 state 的一部分。
所以,我们还会用到一个api-- combineReducers
combineReducers 辅助函数的作用是,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore 方法。
合并后的 reducer 可以调用各个子 reducer,并把它们返回的结果合并成一个 state 对象。
由 combineReducers() 返回的 state 对象,会将传入的每个 reducer 返回的 state 按其传递给 combineReducers() 时对应的 key 进行命名。
示例
rootReducer = combineReducers({potato: potatoReducer, tomato: tomatoReducer})
// 这将返回如下的 state 对象
{
potato: {
// ... potatoes, 和一些其他由 potatoReducer 管理的 state 对象 ...
},
tomato: {
// ... tomatoes, 和一些其他由 tomatoReducer 管理的 state 对象,比如说 sauce 属性 ...
}
}
combineReducers
const reducer = combineReducers({
SidebarCollapsedReducers,
});
改进store
import { createStore, combineReducers } from "redux";
import { SidebarCollapsedReducers } from "./reducers/SidebarCollapsedReducers"; // 导入 SidebarCollapsedReducers
const reducer = combineReducers({
SidebarCollapsedReducers,
});
const store = createStore(reducer);
export default store;
改进根组件
原先app.js
import IndexRouter from './router/IndexRouter'
import './App.css'
function App(){
return <IndexRouter></IndexRouter>
}
export default App
引入 react-redux
改进app.js
import IndexRouter from './router/IndexRouter'
import {Provider} from 'react-redux'
import './App.css'
import store from './redux/store'
function App(){
return <Provider store={store}>
<IndexRouter></IndexRouter>
</Provider>
}
export default App
组件中使用
此功能涉及到两个组件:
- TopHeader.js – 点击按钮部分 ,发布者
- SideMenu.js – 订阅者
如下图
改造 TopHeader.js组件
// TopHeader.js
export default function TopHeader({ pageTitle }) {
// 其他代码
};
引入 react-redux,改进TopHeader.js
补充:connect()
react-redux 提供connect方法,用于从 UI 组件生成容器组件。connect的意思,就是将这两种组件连起来。
connect(
mapStateToProps
mapDispatchToProps
)(被包装的组件)
- mapStateToProps
将state映射到 UI 组件的参数(props)。 const mapStateToProps =state=> state;
- mapDispatchToProps
将用户对 UI 组件的操作映射成 Action。
const mapDispatchToProps = (dispatch)=>{
return {
'Increment':()=> dispatch(IncrementAction({})),
'Decrement':() => dispatch(DecrementAction({})),
}
}
改进TopHeader.js
import {connect} from 'react-redux'
function TopHeader({ pageTitle }) {
const changeCollapsed = ()=>{
// 改变state的状态
props.changeCollapsed()
}
// 其他代码
return <button onClick={()=>changeCollapsed()}>操作</button>
};
const mapStateToProps = (state, ownProps) => {
return {
isCollapsed: state.SidebarCollapsedReducers.isCollapsed
}
}
const mapDispatchToProps = {
changeCollapsed(){
return {
type: 'change_collapsed',
}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(TopHeader);
同理,修改SideMenu.js
import {connect} from 'react-redux'
function SideBar(props) {
// 其他代码
return <Sider collapsed={props.isCollapsed}></Sider> // 注意这里
};
const mapStateToProps = (state, ownProps) => {
return {
isCollapsed: state.SidebarCollapsedReducers.isCollapsed
}
}
export default connect(mapStateToProps)(SideBar);
总结 – 全部代码
\redux\reducers\SidebarCollapsedReducers.js
export const SidebarCollapsedReducers = (prevState = {
isCollapsed: false
}, action) => {
switch (action.type) {
case 'change_collapsed':
let newState = {...prevState} // 注意这里
newState.isCollapsed = !newState.isCollapsed
return newState
default:
return prevState
}
};
\redux\store.js
import { createStore, combineReducers } from "redux";
import { SidebarCollapsedReducers } from "./reducers/SidebarCollapsedReducers"; // 导入 SidebarCollapsedReducers
const reducer = combineReducers({
SidebarCollapsedReducers,
});
const store = createStore(reducer);
export default store;
app.js
import IndexRouter from './router/IndexRouter'
import {Provider} from 'react-redux'
import './App.css'
import store from './redux/store'
function App(){
return <Provider store={store}>
<IndexRouter></IndexRouter>
</Provider>
}
export default App
组件
components\sandbox\TopHeader.js
import React, { useEffect, useState } from "react";
import { Layout} from "antd";
import { connect } from "react-redux";
const { Header } = Layout;
function TopHeader(props) {
const changeCollapsed = ()=>{
// 改变state的状态
// dispatch
console.log(props)
props.changeCollapsed()
}
return (
<Header>
<div style={{ display: "flex" }}>
{React.createElement(
props.isCollapsed ? MenuUnfoldOutlined : MenuFoldOutlined,
{
className: styles.trigger,
onClick: () => changeCollapsed()
}
)}
</div>
</Header>
);
}
const mapStateToProps = (state, ownProps) => {
return {
isCollapsed: state.SidebarCollapsedReducers.isCollapsed
}
}
const mapDispatchToProps = {
changeCollapsed(){
return {
type: 'change_collapsed',
}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(TopHeader);
components\sandbox\SideMenu.js
import { useEffect, useState } from "react";
import { Layout, Menu } from "antd";
import { connect } from "react-redux";
const { Sider } = Layout;
function AppLayout(props) {
return (
<Sider trigger={null} collapsible collapsed={props.isCollapsed}> // 注意这里 props.isCollapsed
<div className={styles.logo}> {siteBaseConfig.siteName} </div>
...
</Sider>
);
}
const mapStateToProps = (state, ownProps) => {
return {
isCollapsed: state.SidebarCollapsedReducers.isCollapsed
}
}
export default connect(mapStateToProps)(AppLayout);
参考文档
- https://cn.redux.js.org/api/combinereducers