React - React Redux 数据共享、Redux DevTools、React Redux 最终优化

一、React Redux 数据共享

1、基本介绍
  • combineReducers 函数用于汇总所有的 Reducer 变为一个总的 Reducer
2、演示
(1)redux
  1. constant
js 复制代码
// 定义 action 中 type 的常量值

export const INCREMENT = "increment";
export const DECREMENT = "decrement";
export const ADD_PERSON = "add_person";
  1. action
js 复制代码
// 该文件专门为 Count 组件生成 action

import { INCREMENT, DECREMENT } from "../constant";

// 同步 action
export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });

// 异步 action,就是 action 的值为函数,异步 action 中一般都会调用同步 action
export const createIncrementAsyncAction = (data, time) => {
    return (dispatch) => {
        setTimeout(() => {
            dispatch(createIncrementAction(data));
        }, time);
    };
};
js 复制代码
import { ADD_PERSON } from "../constant";

export const createAddPersonAction = (data) => ({ type: ADD_PERSON, data });
  1. reducer
js 复制代码
// 该文件是用于创建一个为 Count 组件服务的 Reducer
// Reducer 本质就是一个函数
// Reducer 会接收到两个参数,preState(之前的状态)、action(动作对象)
// 从 action 中可以获取到 type 和 data,根据 type 决定如何加工 data

import { INCREMENT, DECREMENT } from "../constant";

const initState = 0; // 初始状态

export default function countReducer(preState = initState, action) {
    const { type, data } = action;
    switch (type) {
        case INCREMENT:
            return preState + data;
        case DECREMENT:
            return preState - data;
        default:
            return preState;
    }
}
js 复制代码
import { ADD_PERSON } from "../constant";

const initState = [];

export default function personReducer(preState = initState, action) {
    const { type, data } = action;
    switch (type) {
        case ADD_PERSON:
            return [...preState, data];
        default:
            return preState;
    }
}
  1. store
js 复制代码
// 该文件专门用于暴露一个 store 对象,整个应用只有一个 store 对象

import { createStore, applyMiddleware, combineReducers } from "redux";
import countReducer from "./reducers/count";
import personReducer from "./reducers/person";
import thunk from "redux-thunk";

// 汇总所有的 Reducer 变为一个总的 Reducer
const reducer = combineReducers({
    count: countReducer,
    persons: personReducer,
});

// applyMiddleware 用于应用基于 Redux 的中间件
export default createStore(reducer, applyMiddleware(thunk));
(2)container
  1. Count 容器组件
jsx 复制代码
import React, { Component } from "react";

// 引入 action
import { createIncrementAction, createDecrementAction, createIncrementAsyncAction } from "../../redux/actions/count";

// 引入 connect 函数,用于连接组件与 Redux
import { connect } from "react-redux";

class Count extends Component {
    // 加
    increment = () => {
        const { value } = this.selectNumber;
        this.props.jia(value * 1);
    };

    // 减
    decrement = () => {
        const { value } = this.selectNumber;
        this.props.jian(value * 1);
    };

    // 奇数再加
    incrementIfOdd = () => {
        const { value } = this.selectNumber;
        const { count } = this.props;
        if (count % 2 !== 0) {
            this.props.jia(value * 1);
        }
    };

    // 异步加
    incrementAsync = () => {
        const { value } = this.selectNumber;
        this.props.jiaAsync(value * 1, 500);
    };

    render() {
        return (
            <div>
                <h2>当前人员数量为:{this.props.personCount}</h2>
                <h2>当前求和为:{this.props.count}</h2>
                <select ref={(c) => (this.selectNumber = c)}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                &nbsp;
                <button onClick={this.increment}>+</button>&nbsp;
                <button onClick={this.decrement}>-</button>&nbsp;
                <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
                <button onClick={this.incrementAsync}>异步加</button>
            </div>
        );
    }
}

// 1. mapStateToProps 函数返回的是一个对象
// 2. 返回的对象中,key 就作为传递给组件 props 的 key,value 就作为传递给组件 props 的 value
// 3. mapStateToProps 函数用于传递状态
function mapStateToProps(state) {
    return {
        count: state.count,
        personCount: state.persons.length,
    };
}

// 1. mapDispatchToProps 函数返回的是一个对象
// 2. 返回的对象中,key 就作为传递给组件 props 的 key,value 就作为传递给组件 props 的 value
// 3. mapDispatchToProps 函数用于传递操作状态的方法
function mapDispatchToProps(dispatch) {
    return {
        jia: (number) => dispatch(createIncrementAction(number)),
        jian: (number) => dispatch(createDecrementAction(number)),
        jiaAsync: (number, time) => dispatch(createIncrementAsyncAction(number, time)),
    };
}

// 创建并暴露一个 Count 的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(Count);
  1. Person 容器组件
jsx 复制代码
import React, { Component } from "react";
import { nanoid } from "nanoid";
import { connect } from "react-redux";
import { createAddPersonAction } from "../../redux/actions/person";

class Person extends Component {
    addPerson = () => {
        const name = this.nameNode.value;
        const age = this.ageNode.value;
        const personObj = { id: nanoid(), name, age };
        this.props.addPerson(personObj);
        this.nameNode.value = "";
        this.ageNode.value = "";
    };

    render() {
        return (
            <div>
                <h2>求和为 {this.props.count}</h2>
                <input ref={(c) => (this.nameNode = c)} type="text" placeholder="输入名字" />
                <input ref={(c) => (this.ageNode = c)} type="text" placeholder="输入年龄" />
                <button onClick={this.addPerson}>添加</button>
                <ul>
                    {this.props.persons.map((p) => {
                        return (
                            <li key={p.id}>
                                {p.name}--{p.age}
                            </li>
                        );
                    })}
                </ul>
            </div>
        );
    }
}

function mapStateToProps(state) {
    return {
        persons: state.persons,
        count: state.count,
    };
}

// mapDispatchToProps 的简写,如果传入的是对象,就自动用 dispatch 包裹每个方法
const mapDispatchToProps = {
    addPerson: createAddPersonAction,
};

export default connect(mapStateToProps, mapDispatchToProps)(Person);
(3)main
  1. App 组件
jsx 复制代码
import React, { Component } from "react";
import Count from "./containers/Count";
import Person from "./containers/Person";

export default class App extends Component {
    render() {
        return (
            <div>
                <Count />
                <hr />
                <Person />
            </div>
        );
    }
}
  1. index.js
js 复制代码
import React from "react"; // 引入 React 核心库
import ReactDOM from "react-dom"; // 引入 ReactDOM
import App from "./App"; // 引入 App 组件
import store from "./redux/store";
import { Provider } from "react-redux";

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById("root"),
);

二、Redux DevTools

  1. 安装 Edge 浏览器插件 Redux DevTools
  1. 安装 redux-devtools-extension 依赖
shell 复制代码
pnpm install redux-devtools-extension@2.13.8
  1. 使用 redux-devtools-extension 依赖
js 复制代码
// 该文件专门用于暴露一个 store 对象,整个应用只有一个 store 对象

import { createStore, applyMiddleware, combineReducers } from "redux";
import countReducer from "./reducers/count";
import personReducer from "./reducers/person";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";

// 汇总所有的 Reducer 变为一个总的 Reducer
const reducer = combineReducers({
    count: countReducer,
    persons: personReducer,
});

// applyMiddleware 用于应用基于 Redux 的中间件
export default createStore(reducer, composeWithDevTools(applyMiddleware(thunk)));

三、React Redux 最终优化

1、redux
  1. constant
js 复制代码
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
export const ADD_PERSON = "add_person";
  1. action
js 复制代码
import { INCREMENT, DECREMENT } from "../constant";

export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });
export const createIncrementAsyncAction = (data, time) => {
    return (dispatch) => {
        setTimeout(() => {
            dispatch(createIncrementAction(data));
        }, time);
    };
};
js 复制代码
import { ADD_PERSON } from "../constant";

export const createAddPersonAction = (data) => ({ type: ADD_PERSON, data });
  1. reducer
js 复制代码
import { INCREMENT, DECREMENT } from "../constant";

const initState = 0;

export default function countReducer(preState = initState, action) {
    const { type, data } = action;
    switch (type) {
        case INCREMENT:
            return preState + data;
        case DECREMENT:
            return preState - data;
        default:
            return preState;
    }
}
js 复制代码
import { ADD_PERSON } from "../constant";

const initState = [];

export default function personReducer(preState = initState, action) {
    const { type, data } = action;
    switch (type) {
        case ADD_PERSON:
            return [...preState, data];
        default:
            return preState;
    }
}
js 复制代码
import { combineReducers } from "redux";
import countReducer from "./count";
import personReducer from "./person";

export default combineReducers({
    countReducer,
    personReducer,
});
  1. store
js 复制代码
import { createStore, applyMiddleware } from "redux";
import reducer from "./reducers";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";

export default createStore(reducer, composeWithDevTools(applyMiddleware(thunk)));
2、container
  1. Count 容器组件
jsx 复制代码
import { Component } from "react";
import { createIncrementAction, createDecrementAction, createIncrementAsyncAction } from "../../redux/actions/count";
import { connect } from "react-redux";

class Count extends Component {
    // 加
    increment = () => {
        const { value } = this.selectNumber;
        this.props.increment(value * 1);
    };

    // 减
    decrement = () => {
        const { value } = this.selectNumber;
        this.props.decrement(value * 1);
    };

    // 奇数再加
    incrementIfOdd = () => {
        const { value } = this.selectNumber;
        const { countReducer } = this.props;
        if (countReducer % 2 !== 0) {
            this.props.increment(value * 1);
        }
    };

    // 异步加
    incrementAsync = () => {
        const { value } = this.selectNumber;
        this.props.incrementAsync(value * 1, 500);
    };

    render() {
        return (
            <div>
                <h2>当前人员数量为:{this.props.personCount}</h2>
                <h2>当前求和为:{this.props.countReducer}</h2>
                <select ref={(c) => (this.selectNumber = c)}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                &nbsp;
                <button onClick={this.increment}>+</button>&nbsp;
                <button onClick={this.decrement}>-</button>&nbsp;
                <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
                <button onClick={this.incrementAsync}>异步加</button>
            </div>
        );
    }
}

export default connect(
    (state) => ({
        countReducer: state.countReducer,
        personCount: state.personReducer.length,
    }),
    {
        increment: createIncrementAction,
        decrement: createDecrementAction,
        incrementAsync: createIncrementAsyncAction,
    },
)(Count);
  1. Person 容器组件
jsx 复制代码
import { Component } from "react";
import { nanoid } from "nanoid";
import { connect } from "react-redux";
import { createAddPersonAction } from "../../redux/actions/person";

class Person extends Component {
    addPerson = () => {
        const name = this.nameNode.value;
        const age = this.ageNode.value;
        const personObj = { id: nanoid(), name, age };
        this.props.addPerson(personObj);
        this.nameNode.value = "";
        this.ageNode.value = "";
    };

    render() {
        return (
            <div>
                <h2>求和为 {this.props.countReducer}</h2>
                <input ref={(c) => (this.nameNode = c)} type="text" placeholder="输入名字" />
                <input ref={(c) => (this.ageNode = c)} type="text" placeholder="输入年龄" />
                <button onClick={this.addPerson}>添加</button>
                <ul>
                    {this.props.personReducer.map((p) => {
                        return (
                            <li key={p.id}>
                                {p.name}--{p.age}
                            </li>
                        );
                    })}
                </ul>
            </div>
        );
    }
}

export default connect(
    (state) => ({
        countReducer: state.countReducer,
        personReducer: state.personReducer,
    }),
    {
        addPerson: createAddPersonAction,
    },
)(Person);
3、main
  1. App 组件
js 复制代码
import { Component } from "react";
import Count from "./containers/Count";
import Person from "./containers/Person";

export default class App extends Component {
    render() {
        return (
            <div>
                <Count />
                <hr />
                <Person />
            </div>
        );
    }
}
  1. index.js
js 复制代码
import ReactDOM from "react-dom";
import App from "./App";
import store from "./redux/store";
import { Provider } from "react-redux";

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById("root"),
);
相关推荐
英俊潇洒美少年2 小时前
数据驱动视图 vue和react对比
javascript·vue.js·react.js
Jinuss2 小时前
源码分析之React中的createContext/useContext详解
前端·javascript·react.js
代码搬运媛2 小时前
幽灵依赖终结者:pnpm 的 node_modules 结构隔离深度解析
前端
不喝水的鱼儿2 小时前
KT Qwen3.5-35B-A3B 记录
java·前端·python
AnalogElectronic2 小时前
uniapp学习7,美团闪购生鲜蔬菜商家详情页
javascript·学习·uni-app
切糕师学AI2 小时前
深入解析前端页面在 Safari 与 Chrome 浏览器中的差异及解决方案
前端·chrome·safari
琪伦的工具库2 小时前
在自动化部署流程中集成视频转GIF:工具选型与参数调优
javascript·自动化·音视频
fengtangjiang2 小时前
tomcat和国产web中间件区别和联系
前端·中间件·tomcat
永远的个初学者2 小时前
一个同时支持 React、Vue、Node、CLI、Vite、Webpack 的图片优化库:rv-image-optimize
vue.js·react.js·webpack