文章目录
1. redux 是什么
- redux 是一个专门用于做状态管理的 JS 库 (不是 react 插件库)
- 它可以用在各种项目中,但是基本与 react 配合使用
- 作用:集中式管理 react 应用中多个组件共享的状态
2. 什么时候使用 redux
- 多个组件依赖于同一状态
- 多个组件所依赖的数据都是相互影响的,组件 A 中共享数据的更改,组件 B 中共享的同一数据默认也会改
3. redux 安装与使用
3.1 安装
// 使用 npm 安装
npm i redux
3.2 完整使用
-
创建
redux/store.js
文件,存放数据// 用于创建一个 store import { createStore } from "redux" // 用于 Count 组件服务的 reducer import countReducer from "./count_reducer.js" export default createStore(countReducer)
-
创建
redux/count_reducer.js
文件,处理数据import { ADD, SUB } from "./constant.js" // preState:表示初始值,或前一次状态的值 export default function countReducer(preState = 0, action){ // action:它是一个对象,包含了方法和数据 let { type, data } = action switch(type) { case ADD: return preState + data case SUB: return preState - data default: return preState // 必须要返回一个新值或初始值 } }
-
创建
redux/count_action.js
文件,提供方法import { ADD, SUB } from "./constant.js" // action 需要返回一个对象,type:方法名、data:数据 export const addAction = data => ({ type: ADD, data }) export const subAction = data => ({ type: SUB, data })
-
创建
redux/constant.js
文件,命名空间// 因为 type 方法名称在多处都会使用到,这样写便于管理,还可以防止程序员写错 export const ADD = "add" export const SUB = "sub"
-
组件中使用 store
import { Component } from "react"; import store from "./src/redux/store.js" import { addAction, subAction } from "./src/redux/count_action.js" export default class Count extends Component { componentDidMount() { /* store 中的值发生了改变,并不会调用自动 render 当 store 中的值发生了改变,store.subscribe 会触发回调,然后使用 this.setState 强制调用 render 这样写有一点不好,就是每在一个组件使用一次,都需要再去写一遍,可以直接在入口文件中使用 这样只要有一个组件中的 redux 值发生了改变,就会更新视图 store.subscribe(() => { ReactDOM.render(<App />, document.getElement("root")) }) */ store.subscribe(() => { this.setState({}) }) } add = (data) => { // dispatch 会触发 reducer 函数(这里指 countReducer 函数) store.dispatch(addAction(data)) } sub = (data) => { store.dispatch(subAction(data)) } render() { return ( // getState 使用数据,store 本身是一个对象 <div>{ store.getState() }</div> ) } }
3.3 异步 action
// 当 action 为函数时,它将会成为一个异步 action
import { createStore, applyMiddleware } from "redux"
// 引入 redux-thunk,用于支持异步 action
import thunk from "redux-thunk"
// 此时暴露时,需要执行中间件
export default createStore(countReducer, applyMiddleware(thunk))
// 这个时候写 action 时,就可以返回函数了
// 异步函数里面还是调用的同步函数
export const addAsyncAction = (data, time) => {
return (dispath) => {
setTimeout(() => {
dispath(addAction(data))
},time)
}
}
store.dispatch(addAsyncAction(data, 300))
4. react-redux 的理解
- react-redux 是对 redux 的封装,成为了 react 的一个插件库
- react-redux 中所有的容器组件都应该包裹一个UI组件,他们为父子关系
- 只有容器组件才能调用 react-redux 中的方法,store.getState()、store.dispath(action)
- UI组件的状态和方法,只能通过 props 传递
5. react-redux 安装与使用
5.1 安装
npm i react-redux
5.2 连接容器组件和UI组件
-
容器组件,连接容器组件和UI组件
// count 容器组件,容器组件要写在 container 文件下,UI组件要写在 component 文件下 import CountUI from "./component/Count" // 用于连接 UI 和 store,但此时只连接了 UI import { connect } from "react-redux" export default connect()(CountUI) // 有了 connect 函数不需要在手动检测数据的变化了
-
引入容器组件,连接容器组件和 store
// 使用组件时,要使用容器组件 import Count from "./container/Count" // 使用时需要把 store 作为 prop 值传过去 import store from "./redux/store" export default class Demo extends Componet { render(){ return <Count store={store}></Count> } }
-
UI组件
// 正常写页面就可以了
5.3 基本使用
// 容器组件
import { connect } from "react-redux"
import CountUI from "../component/Count"
import { addAction } from "../redux/count_action"
// 该函数返回一个存状态的对象,会把该对象的值映射到 CountUI 组件的 props 中
function mapStateToProps(state){
return {
// state ==> store.getState()
count: state
}
}
// 该函数返回一个存方法的对象,映射到 props 中
function mapDispatchToProps(dispatch){
return {
// dispatch ==> store.dispath
add: (data) => {
dispatch(addAction(data))
}
}
}
// 此时连接了 UI 和 store
export default connect(mapStateToProps, mapStateToProps)(CountUI)
// UI组件
export default class CountUI extends Componet {
return(){
console.log(this.porps) // {store: {…}, count: 0, add: ƒ},这里也可以拿到 store 对象
}
}
6. react-redux 优化
6.1 简写 mapDispatchToProps
// 优化前
import { connect } from "react-redux";
import countUI from "../components/CountUI.jsx";
import { addAction, subAction, addAsyncAction } from "../redux/count_action";
export default connect(
(state) => ({
count: state,
}),
// 当 mapDispatchToProps 为对象时,可以直接把函数赋值过去
{
add: addAction,
sub: subAction,
addAsync: addAsyncAction,
}
)(countUI);
6.2 使用 Provider 组件
import React from "react";
import reactDOM from "react-dom";
import { Provider } from "react-redux";
import store from "./redux/store";
import App from "./App.jsx";
// 在这里使用 Provider 组件传入 store 值,使后续的所有组件都不需要再次传入 store
reactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
6.3 合并UI组件和容器组件
import React, { Component } from "react";
import { connect } from "react-redux";
import { addAction, subAction, addAsyncAction } from "../redux/count_action";
// UI组件部分
class countUI extends Component {
add = () => {
let { value } = this.selectNode;
this.props.add(Number(value));
};
sub = () => {
let { value } = this.selectNode;
this.props.sub(Number(value));
};
addAsync = () => {
let { value } = this.selectNode;
this.props.addAsync(Number(value), 500);
};
render() {
let { count } = this.props;
return (
<div>
<div>
<h1>{count}</h1>
<select ref={(curNode) => (this.selectNode = curNode)}>
<option>1</option>
<option>2</option>
<option>3</option>
</select>
<button onClick={this.add}>点我加</button>
<button onClick={this.sub}>点我减</button>
<button onClick={this.addAsync}>异步加</button>
</div>
</div>
);
}
}
// connect 连接部分
export default connect (
(state) => ({
count: state,
}),
{
add: addAction,
sub: subAction,
addAsync: addAsyncAction,
}
)(countUI);
7. 数据共享
7.1 文件结构
|-- redux // 数据处理的总文件夹
|-- reducers // 集中管理reducer
|-- demo1.js // 第一个reducer
|-- demo2.js // 第二...
|-- index.js // reducers的汇总
|-- actions // 集中管理action
|-- demo1.js // 第一个action
|-- demo2.js // 第二...
|-- constant.js // 命名空间
|-- sotre.js // 主文件,存放状态