React 全栈体系(十四)

第七章 redux

六、react-redux

7. 代码 - react-redux 数据共享版

7.1 效果

请添加图片描述

7.2 App
/* src/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>
    );
  }
}
7.3 Count
/* src/containers/Count/index.jsx */
import React, {
    
     Component } from "react";
import {
    
    
  createIncrementAction,
  createDecrementAction,
  createIncrementAsyncAction,
} from "../../redux/actions/count";

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

// 定义UI组件
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;
    if (this.props.count % 2 !== 0) {
    
    
      this.props.jia(value * 1);
    }
  };
  //异步加
  incrementAsync = () => {
    
    
    const {
    
     value } = this.selectNumber;
    this.props.jiaAsync(value * 1, 500);
  };
  render() {
    
    
    return (
      <div>
        <h2>我是Count组件,下方组件总人数为:{
    
    this.props.renshu}</h2>
        <h4>
          当前求和为:{
    
    this.props.count}
        </h4>
        <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>
    );
  }
}

//使用connect()()创建并暴露一个Count的容器组件
export default connect(
  (state) => ({
    
     count: state.he, renshu: state.rens.length }),
  {
    
    
    jia: createIncrementAction,
    jian: createDecrementAction,
    jiaAsync: createIncrementAsyncAction,
  }
)(Count);
7.4 Person
/* src/containers/Person/index.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.jiaYiRen(personObj);
    this.nameNode.value = "";
    this.ageNode.value = "";
  };
  render() {
    
    
    return (
      <div>
        <h2>我是Person组件,上方组件求和为{
    
    this.props.he}</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.yiduiren.map((p) => {
    
    
            return (
              <li key={
    
    p.id}>
                {
    
    p.name}--{
    
    p.age}
              </li>
            );
          })}
        </ul>
      </div>
    );
  }
}

export default connect(
  (state) => ({
    
     yiduiren: state.rens, he: state.he }), //映射状态
  {
    
     jiaYiRen: createAddPersonAction } //映射操作状态的方法
)(Person);
7.5 store
/* src/redux/store.js */
/**
 * 该文件专门用于暴露一个store对象,整个应用只有一个store对象
 */
//引入createStore,专门用于创建redux中最为核心的store对象
import {
    
     createStore, applyMiddleware, combineReducers } from "redux";
//引入为Count组件服务的reducer
import countReducer from "./reducers/count";
//引入为Person组件服务的reducer
import personReducer from "./reducers/person";
//引入redux-thunk,用于支持异步action
import thunk from "redux-thunk";

//汇总所有的reducer变为一个总的reducer
const allReducer = combineReducers({
    
    
  he: countReducer,
  rens: personReducer,
});
//暴露store
export default createStore(allReducer, applyMiddleware(thunk));
7.6 constant
/* src/redux/constant.js */
/**
 * 该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
 */
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
export const ADD_PERSON = "add_person";
7.7 actions
7.5.1 count
/* src/redux/actions/count.js */
/**
 * 该文件专门为Count组件生成action对象
 */
import {
    
     INCREMENT, DECREMENT } from "../constant";

//同步action,就是指action的值为Object类型的一般对象
export const createIncrementAction = (data) => ({
    
     type: INCREMENT, data });
export const createDecrementAction = (data) => ({
    
     type: DECREMENT, data });

//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的
export const createIncrementAsyncAction = (data, time) => {
    
    
  return (dispatch) => {
    
    
    setTimeout(() => {
    
    
      dispatch(createIncrementAction(data));
    }, time);
  };
};
7.5.2 person
/* src/redux/actions/person.js */
import {
    
     ADD_PERSON } from "../constant";

//创建增加一个人的action动作对象
export const createAddPersonAction = (personObj) => ({
    
    
  type: ADD_PERSON,
  data: personObj,
});
7.8 reducers
7.8.1 count
/* src/redux/reducers/count.js */
/**
 * 1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
 * 2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
 */
import {
    
     INCREMENT, DECREMENT } from "../constant";

const initState = 0;
export default function countReducer(preState = initState, action) {
    
    
  //从action对象中获取:type、data
  const {
    
     type, data } = action;
  //根据type决定如何加工数据
  switch (type) {
    
    
    case INCREMENT: //如果是加
      return preState + data;
    case DECREMENT: //如果是减
      return preState - data;
    default:
      return preState;
  }
}
7.8.2 person
/* src/redux/reducers/person.js */
import {
    
     ADD_PERSON } from "../constant";

//初始化人的列表
const initState = [{
    
     id: "001", name: "tom", age: 18 }];

export default function personReducer(preState = initState, action) {
    
    
  const {
    
     type, data } = action;
  switch (type) {
    
    
    case ADD_PERSON:
      return [data, ...preState];
    default:
      return preState;
  }
}
7.9 总结
(1).定义一个Person组件,和Count组件通过redux共享数据。
(2).为Person组件编写:reducer、action,配置constant常量。
(3).重点:Person的reducer和Count的Reducer要使用combineReducers进行合并,
		合并后的总状态是一个对象!!!
(4).交给store的是总reducer,最后注意在组件中取出状态的时候,记得“取到位”。

七、纯函数和高阶函数

1. 纯函数

  • 一类特别的函数: 只要是同样的输入(实参),必定得到同样的输出(返回)
  • 必须遵守以下一些约束
    • 不得改写参数数据
    • 不会产生任何副作用,例如网络请求,输入和输出设备
    • 不能调用 Date.now()或者 Math.random()等不纯的方法
  • redux 的 reducer 函数必须是一个纯函数

2. 高阶函数

  • 理解: 一类特别的函数
    • 情况 1: 参数是函数
    • 情况 2: 返回是函数
  • 常见的高阶函数:
    • 定时器设置函数
    • 数组的 forEach()/map()/filter()/reduce()/find()/bind()
    • promise
    • react-redux 中的 connect 函数
  • 作用: 能实现更加动态, 更加可扩展的功能

八、使用 redux 调试工具

1. 安装 chrome 浏览器插件

请添加图片描述

2. 下载工具依赖包

  • npm install --save-dev redux-devtools-extension

3. 总结

(1).yarn add redux-devtools-extension
(2).store中进行配置
	import {
    
    composeWithDevTools} from 'redux-devtools-extension'
	const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))

九、react-redux 最终版

请添加图片描述

1. index.js

/* src/index.js */
//引入react核心库
import React from "react";
//引入ReactDOM
import ReactDOM from "react-dom";
//引入App组件
import App from "./App";
import store from "./redux/store";
import {
    
     Provider } from "react-redux";

ReactDOM.render(
  /** 此处需要用Provider包裹App,目的是让App所有的后代容器组件都能接收到store */
  <Provider store={
    
    store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

2. App.jsx

/* src/App.jsx */
import React, {
    
     Component } from "react";
import Count from "./containers/Count"; //引入的Count容器组件
import Person from "./containers/Person"; //引入的Person容器组件

export default class App extends Component {
    
    
  render() {
    
    
    return (
      <div>
        <Count />
        <hr />
        <Person />
      </div>
    );
  }
}

3. store.js

/* src/redux/store.js */
/**
 * 该文件专门用于暴露一个store对象,整个应用只有一个store对象
 */
//引入createStore,专门用于创建redux中最为核心的store对象
import {
    
     createStore, applyMiddleware } from "redux";
//引入汇总之后的reducer
import reducer from "./reducers";
//引入redux-thunk,用于支持异步action
import thunk from "redux-thunk";

//暴露store
export default createStore(reducer, applyMiddleware(thunk));

4. containers

4.1 Count
/* src/containers/Count/index.jsx */
import React, {
    
     Component } from "react";
import {
    
    
  increment,
  decrement,
  incrementAsync,
} from "../../redux/actions/count";

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

// 定义UI组件
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;
    if (this.props.count % 2 !== 0) {
    
    
      this.props.increment(value * 1);
    }
  };
  //异步加
  incrementAsync = () => {
    
    
    const {
    
     value } = this.selectNumber;
    this.props.incrementAsync(value * 1, 500);
  };
  render() {
    
    
    return (
      <div>
        <h2>我是Count组件,下方组件总人数为:{
    
    this.props.personCount}</h2>
        <h4>当前求和为:{
    
    this.props.count}</h4>
        <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>
    );
  }
}

//使用connect()()创建并暴露一个Count的容器组件
export default connect(
  (state) => ({
    
    
    count: state.count,
    personCount: state.persons.length,
  }),
  {
    
    
    increment,
    decrement,
    incrementAsync,
  }
)(Count);
4.2 Person
/* src/containers/Person/index.jsx */
import React, {
    
     Component } from "react";
import {
    
     nanoid } from "nanoid";
import {
    
     connect } from "react-redux";
import {
    
     addPerson } from "../../redux/actions/person";

class Person extends Component {
    
    
  addPerson = () => {
    
    
    const name = this.nameNode.value;
    const age = this.ageNode.value * 1;
    const personObj = {
    
     id: nanoid(), name, age };
    this.props.addPerson(personObj);
    this.nameNode.value = "";
    this.ageNode.value = "";
  };
  render() {
    
    
    return (
      <div>
        <h2>我是Person组件,上方组件求和为{
    
    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.personArr.map((p) => {
    
    
            return (
              <li key={
    
    p.id}>
                {
    
    p.name}--{
    
    p.age}
              </li>
            );
          })}
        </ul>
      </div>
    );
  }
}

export default connect(
  (state) => ({
    
    
    personArr: state.persons,
    count: state.count,
  }), //映射状态
  {
    
     addPerson } //映射操作状态的方法
)(Person);

5. reducers

5.1 index
/* src/redux/reducers/index.js */
/**
 * 该文件用于汇总所有的reducer为一个总的reducer
 */
//引入combineReducers,用于汇总多个reducer
import {
    
     combineReducers } from "redux";

//引入为Count组件服务的reducer
import count from "./count";
//引入为Person组件服务的reducer
import persons from "./person";

//汇总所有的reducer变为一个总的reducer
export default combineReducers({
    
    
  count,
  persons
});
5.2 count
/* src/redux/reducers/count.js */
/**
 * 1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
 * 2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
 */
import {
    
     INCREMENT, DECREMENT } from "../constant";

const initState = 0;
export default function countReducer(preState = initState, action) {
    
    
  //从action对象中获取:type、data
  const {
    
     type, data } = action;
  //根据type决定如何加工数据
  switch (type) {
    
    
    case INCREMENT: //如果是加
      return preState + data;
    case DECREMENT: //如果是减
      return preState - data;
    default:
      return preState;
  }
}
5.3 person
/* src/redux/reducers/person.js */
import {
    
     ADD_PERSON } from "../constant";

//初始化人的列表
const initState = [{
    
     id: "001", name: "tom", age: 18 }];

export default function personReducer(preState = initState, action) {
    
    
  const {
    
     type, data } = action;
  switch (type) {
    
    
    case ADD_PERSON:
      return [data, ...preState];
    default:
      return preState;
  }
}

6. actions

6.1 count
/* src/redux/actions/count.js */
/**
 * 该文件专门为Count组件生成action对象
 */
import {
    
     INCREMENT, DECREMENT } from "../constant";

//同步action,就是指action的值为Object类型的一般对象
export const increment = (data) => ({
    
     type: INCREMENT, data });
export const decrement = (data) => ({
    
     type: DECREMENT, data });

//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的
export const incrementAsync = (data, time) => {
    
    
  return (dispatch) => {
    
    
    setTimeout(() => {
    
    
      dispatch(increment(data));
    }, time);
  };
};
6.2 person
/* src/redux/actions/person.js */
import {
    
     ADD_PERSON } from "../constant";

//创建增加一个人的action动作对象
export const addPerson = (personObj) => ({
    
    
  type: ADD_PERSON,
  data: personObj,
});

7. 总结

(1).所有变量名字要规范,尽量触发对象的简写形式。
(2).reducers文件夹中,编写index.js专门用于汇总并暴露所有的reducer

十、项目打包

npm run build

npm install -g serve
serve -s build

请添加图片描述

猜你喜欢

转载自blog.csdn.net/sgsgkxkx/article/details/133189340