ReactJS语法-redux

redux

JavaScript纯函数

  1. 函数式编程中有一个非常重要的概念叫纯函数,JavaScript符合函数式编程的范式,所以也有纯函数的概念;
  2. 纯函数特点:
    1. 确定的输入,一定会产生确定的输出;
    2. 函数在执行过程中,不能产生副作用;
  3. 副作用:表示在执行一个函数时,除了返回函数值之外,还对调用函数产生了附加的影响,比如修改了全局变量,修改参数或者改变外部的存储;
  4. 举例:
    1. slice:slice截取数组时不会对原数组进行任何操作,而是生成一个新的数组;
    2. splice:splice截取数组, 会返回一个新的数组, 也会对原数组进行修改;
    3. slice就是一个纯函数,不会修改数组本身,而splice函数不是一个纯函数;
  5. 举例2

     //该函数就是一个纯函数,1有确定的输入,就能够有确定的输出。2. 函数执行对外部没有任何副作用
     function sum(num1,num2){
         return num1+num2;
     }
        
     //这个函数就不是一个纯函数,因为引用了外部的变量,外部变量可以随时修改,那么就不能保证确定的输入有确定的输出。
     let foo = 5;
     function add(num1){
         return num1+foo;
     }
        
     //不是纯函数,因为函数内部修改了外部的数据,产生了新的副作用
     function printInfo(info){
         info.name = "hhh";
         return info;
     }
    
  6. React中就要求我们无论是函数还是class声明一个组件,这个组件都必须像纯函数一样,保护它们的props不被修改。

为什么需要redux

  1. JavaScript需要管理的状态越来越多,越来越复杂;这些状态包括服务器返回的数据、缓存数据、用户操作产生的数据等等,也包括一些UI的状态,比如某些元素是否被选中,是否显示加载动效,当前分页;
  2. Redux就是一个帮助我们管理State的容器:Redux是JavaScript的状态容器,提供了可预测的状态管理;

几个核心概念

  1. Store:定义统一的规范来操作这段数据。
  2. action
    1. Redux要求我们通过action来更新数据
    2. 所有数据的变化,必须通过派发(dispatch)action来更新;
    3. action是一个普通的JavaScript对象,用来描述这次更新的type和content;
    4. 强制使用action的好处是可以清晰的知道数据到底发生了什么样的变化,所有的数据变化都是可跟追、可预测的;
  3. reducer
    1. 但是如何将state和action联系在一起呢?答案就是reduce
    2. reducer是一个纯函数;
    3. reducer做的事情就是将传入的state和action结合起来生成一个新的state;

Redux的三大原则

  1. 单一数据源
    1. 整个应用程序的state被存储在一颗object tree中,并且这个object tree只存储在一个 store 中:
    2. 单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改;
  2. State是只读的
    1. 唯一修改State的方法一定是触发action,不要试图在其他地方通过任何的方式来修改State:
    2. 这样就确保了View或网络请求都不能直接修改state,它们只能通过action来描述自己想要如何修改state;
    3. 这样可以保证所有的修改都被集中化处理,并且按照严格的顺序来执行,所以不需要担心race condition(竟态)的问题;
    4. 使用纯函数来执行修改
  3. 使用纯函数来执行修改
    1. 通过reducer将 旧state和 actions联系在一起,并且返回一个新的State:
    2. 随着应用程序的复杂度增加,我们可以将reducer拆分成多个小的reducers,分别操作不同state tree的一部分;
    3. 但是所有的reducer都应该是纯函数,不能产生任何的副作用

Redux的使用

  1. 创建一个对象,作为我们要保存的状态:
  2. 创建Store来存储这个state
    1. 创建store时必须创建reducer;
    2. 我们可以通过 store.getState 来获取当前的state;
  3. 通过action来修改state
    1. 通过dispatch来派发action;
    2. 通常action中都会有type属性,也可以携带其他的数据;
  4. 修改reducer中的处理代码
    1. 这里一定要记住,reducer是一个纯函数,不需要直接修改state;
  5. 可以在派发action之前,监听store的变化:

案例

  1. 创建store/index.js文件:

     //这里是nodejs环境,因此使用require引入
     const { createStore } = require("redux")
        
     //2. 创建store时必须创建reducer;
     const reducer =  require("./reducer.js")
     //1. 创建的store
     const store = createStore(reducer)
        
     module.exports = store
    
  2. 创建store/reducer.js文件:

     const { ADD_NUMBER, CHANGE_NAME } = require("./constants")
    
     // 初始化的数据
     const initialState = {
       name: "why",
       counter: 100
     }
        
     //store首次被创建的时候,state没有值,因此可以设置默认值。后序使用state就代表现状的值
     function reducer(state = initialState, action) {
       switch(action.type) {
         case CHANGE_NAME:
           //1. 对原有的state进行深拷贝。2. 修改新的state的name值。 3. 返回新的state
           return { ...state, name: action.name }
         case ADD_NUMBER:
           return { ...state, counter: state.counter + action.num }
         default:
           return state
       }
     }
        
     module.exports = reducer
    
  3. 创建store/actionCreators.js文件:

     //封装一个对象,用于快速创建一个action
     const { ADD_NUMBER, CHANGE_NAME } = require("./constants")
    
     const changeNameAction = (name) => ({
       type: CHANGE_NAME,
       //等价于 num : num
       name
     })
        
     const addNumberAction = (num) => ({
       type: ADD_NUMBER,
       num
     })
        
        
     module.exports = {
       changeNameAction,
       addNumberAction
     }
    
  4. 创建store/constants.js文件

     //常量记录
     const ADD_NUMBER = "add_number"
     const CHANGE_NAME = "change_name"
        
     module.exports = {
       ADD_NUMBER,
       CHANGE_NAME
     }
    
  5. 外部文件使用store

     const store = require("./store")
     const { addNumberAction, changeNameAction } = require("./store/actionCreators")
     //在派发action之前,监听store的变化:
     const unsubscribe = store.subscribe(() => {
      //使用store中的数据
       console.log("订阅数据的变化:", store.getState())
     })
        
     // 修改store中的数据: 必须action
     store.dispatch(changeNameAction("kobe"))
     store.dispatch(addNumberAction(10))
        
     //取消订阅
     unsubscribe()
    

react中使用redux

  1. redux和react没有直接的关系,你完全可以在React, Angular, Ember, jQuery, JavaScript中使用Redux
  2. 安装redux:npm install redux
  3. 举例:
    1. App.jsx

       import React, { PureComponent } from 'react'
       import Home from './pages/home'
       import Profile from './pages/profile'
       import store from "./store"
              
       export class App extends PureComponent {
         constructor() {
           super()
              
           this.state = {
             counter: store.getState().counter.counter
           }
         }
              
         componentDidMount() {
           store.subscribe(() => {
             const state = store.getState().counter
             this.setState({ counter: state.counter })
           })
         }
              
         render() {
           const { counter } = this.state
              
           return (
             <div>
               <h2>App Counter: {counter}</h2>
              
               <div className='pages'>
                 <Home/>
                 <Profile/>
               </div>
             </div>
           )
         }
       }
       export default App
      
    2. Home.jsx

       import React, { PureComponent } from 'react'
       import store from "../store"
       import { addNumberAction } from '../store/actionCreators'
              
       export class Home extends PureComponent {
         constructor() {
           super()
              
           this.state = {
             counter: store.getState().counter,
           }
         }
              
         componentDidMount() {
           store.subscribe(() => {
             const state = store.getState()
             this.setState({ counter: state.counter })
           })
         }
              
         addNumber(num) {
           store.dispatch(addNumberAction(num))
         }
              
         render() {
           const { counter } = this.state
              
           return (
             <div>
               <h2>Home Counter: {counter}</h2>
               <div>
                 <button onClick={e => this.addNumber(1)}>+1</button>
                 <button onClick={e => this.addNumber(5)}>+5</button>
               </div>
             </div>
           )
         }
       }
              
       export default Home
      
    3. Profile.jsx

       import React, { PureComponent } from 'react'
       import store from "../store"
       import { subNumberAction } from '../store/actionCreators'
              
       export class Profile extends PureComponent {
         constructor() {
           super()
              
           this.state = {
             counter: store.getState().counter
           }
         }
              
         componentDidMount() {
           store.subscribe(() => {
             const state = store.getState()
             this.setState({ counter: state.counter })
           })
         }
              
         subNumber(num) {
           store.dispatch(subNumberAction(num))
         }
              
         render() {
           const { counter } = this.state
              
           return (
             <div>
               <h2>Profile Counter: {counter}</h2>
               <div>
                 <button onClick={e => this.subNumber(1)}>-1</button>
                 <button onClick={e => this.subNumber(5)}>-5</button>
               </div>
             </div>
           )
         }
       }
       export default Profile
      
    4. store文件夹下

     // index.js
     import { createStore, applyMiddleware, compose } from "redux"
     import reducer from "./reducer"
     const store = createStore(reducer)
        
     export default store
        
     //reducer.js
     import * as actionTypes from "./constants"
     const initialState = {
       counter: 100
     }
        
     function reducer(state = initialState, action) {
       switch (action.type) {
         case actionTypes.ADD_NUMBER:
           return { ...state, counter: state.counter + action.num }
         case actionTypes.SUB_NUMBER:
           return { ...state, counter: state.counter - action.num }
         default:
           return state
       }
     }
        
     export default reducer
        
     //actionCreators.js
     import * as actionTypes from "./constants"
     export const addNumberAction = (num) => ({
       type: actionTypes.ADD_NUMBER,
       num
     })
        
     export const subNumberAction = (num) => ({
       type: actionTypes.SUB_NUMBER,
       num
     })
    

react-redux使用

  1. 从上面的案例可以看出,App.jsx、Home.jsx、Profile.jsx如果要使用redux,都必须要:
    1. constructor中获取store数据对state初始化
    2. componentDidMount中订阅store数据的变化,然后重新渲染页面
    3. 操作store对数据数据进行更新
  2. 那么是否可以将以上操作使用一个高阶组件进行抽取封装起来,应用组件只需要:
    1. 告知哪些state数据需要被初始化
    2. 哪些数据需要被更新
  3. 这个就是react-redux的作用

举例使用:

  1. 安装: npm install react-redux
  2. 在入口index.js文件中

     import React from 'react';
     import ReactDOM from 'react-dom/client';
     import App from './App';
     //1. 引用Provider
     import { Provider } from "react-redux"
     //2. 引用store
     import store from "./store"
        
     const root = ReactDOM.createRoot(document.getElementById('root'));
     root.render(
         {/*3. 使用Provider组件包裹App组件,并将store作为传参,目的是为了react-redux内部能够拿到store来操作*/}
         <Provider store={store}>
           <App />
         </Provider>
     );
    
  3. 新增一个About.jsx

     import React, { PureComponent } from 'react'
     //1. 引入connect
     import { connect } from "react-redux"
     import { addNumberAction, subNumberAction } from '../store/actionCreators'
        
     export class About extends PureComponent {
        
       calcNumber(num, isAdd) {
         if (isAdd) {
           console.log("加", num)
           // 3.1. this.props可以拿到addNumber函数用来修改stroe的数据
           this.props.addNumber(num)
         } else {
           console.log("减", num)
           this.props.subNumber(num)
         }
       }
        
       render() {
         // 3.2. this.props可以拿到counter用来展示数据
         const { counter } = this.props
         return (
           <div>
             <h2>About Page: {counter}</h2>
             <div>
               <button onClick={e => this.calcNumber(6, true)}>+6</button>
               <button onClick={e => this.calcNumber(6, false)}>-6</button>
             </div>
           </div>
         )
       }
     }
        
     // connect()返回值是一个高阶组件
     // function mapStateToProps(state) {
     //   return {
     //     counter: state.counter
     //   }
     // }
        
     // function fn2(dispatch) {
     //   return {
     //     addNumber(num) {
     //       dispatch(addNumberAction(num))
     //     },
     //     subNumber(num) { 
     //       dispatch(subNumberAction(num))
     //     }
     //   }
     // }
        
     const mapStateToProps = (state) => ({
       counter: state.counter,
       banners: state.banners,
       recommends: state.recommends
     })
        
     const mapDispatchToProps = (dispatch) => ({
       addNumber(num) {
         dispatch(addNumberAction(num))
       },
       subNumber(num) {
         dispatch(subNumberAction(num))
       }
     })
        
     /*
     1. 调用connect这个高阶函数
     2.1. connect是一个高阶函数,传参为2个函数
     2.2. 第一个函数参数:告诉react-redux需要将state的哪个属性进行初始化、监听渲染、传递给当前的About组件的Props属性用来获取。
     2.3. 第二个函数参数:告诉react-redux需要修改state的那个属性值,并将这个函数传递给About组件的Props属性用来调用
     2.4. connect的返回值是一个高阶组件,传参为组件,返回值是一个新的组件
     内部原理------:
     通过调用mapStateToProps,拿到当前About组件state那个属性,那么就可以确定store的哪个属性需要被被监听,然后将监听变更后的结果以props的方式传递给About组件
     通过调用mapDispatchToProps,可以拿到变更store数据的函数实现,然后赋值给About组件的props,这样About就可以调用自己的props方法来修改store
     */
     export default connect(mapStateToProps, mapDispatchToProps)(About)
    
  4. 新增一个APP.jsx使用

     render() {
         const { counter } = this.state
         return (
           <div>
             <h2>App Counter: {counter}</h2>
             <div className='pages'>
               <Home/>
               <Profile/>
               <About/>
             </div>
           </div>
         )
     }
    

redux存储异步网络请求的数据

  1. 创建一个组件专门用来获取网络请求的数据Category.jsx

     import React, { PureComponent } from 'react'
     import { connect } from "react-redux"
     //actionCreators新增一个action方法
     import { fetchHomeMultidataAction } from "../store/actionCreators"
        
     export class Category extends PureComponent {
        
       componentDidMount() {
         //获取网络请求,并将网络请求数据存储到store
         this.props.fetchHomeMultidata()
       }
        
       render() {
         return (
           <div>
           </div>
         )
       }
     }
        
     const mapDispatchToProps = (dispatch) => ({
       //网络请求数据方法实现
       fetchHomeMultidata() {
         //修改store,通常dispatch的参数只能是一个action对象,但是这里fetchHomeMultidataAction()返回值是一个函数
         dispatch(fetchHomeMultidataAction())
       }
     })
        
     export default connect(null, mapDispatchToProps )(Category)
    
  2. actionCreators实现fetchHomeMultidataAction函数

     import * as actionTypes from "./constants"
     import axios from "axios"
        
     export const addNumberAction = (num) => ({
       type: actionTypes.ADD_NUMBER,
       num
     })
        
     export const subNumberAction = (num) => ({
       type: actionTypes.SUB_NUMBER,
       num
     })
        
     //封装一个acion,直接存放服务器返回的banners数据
     export const changeBannersAction = (banners) => ({
       type: actionTypes.CHANGE_BANNERS,
       banners
     })
        
     /*
     1. 这个方法通常返回的是一个action对象
     2. 理论上是先获取网络请求的数据,然后将数据封装到aciton中去
     3. 但是网络请求时异步的,因此无法直接返回
     4. 解决办法:返回一个函数,同时将dispatch、state传参,在这个函数实现里面去网络请求,等网络请求回来之后在进行dispatch修改store数据
     5. 为了让action方法支持返回一个函数,需要使用第三方库:redux-thunk,即npm install redux-thunk
     */
     export const fetchHomeMultidataAction = () => {
       // 如果是一个普通的action, 那么我们这里需要返回action对象
       // 问题: 对象中是不能直接拿到从服务器请求的异步数据的
       // return {}
        
       return function(dispatch, getState) {
         // 异步操作: 网络请求
         // console.log("foo function execution-----", getState().counter)
         axios.get("http://123.207.32.32:8000/home/multidata").then(res => {
           const banners = res.data.data.banner.list
           //实际修改store数据
           dispatch(changeBannersAction(banners))
         })
       }
     }
    
  3. index.js

     import { createStore, applyMiddleware } from "redux"
     import thunk from "redux-thunk"
     //store通过thunk做了一个增强,在修改store时dispatch可以传递函数,而且一旦传递函数,会直接调用,并传参dispatch, getState
     const store = createStore(reducer,applyMiddleware(thunk))
     export default store
    

redux-thunk是如何做到让我们可以发送异步的请求

  1. 默认情况下的dispatch(action),action需要是一个JavaScript的对象;
  2. redux-thunk可以让dispatch(action函数),action可以是一个函数;
  3. 该函数会被调用,并且会传给这个函数一个dispatch函数和getState函数;
    1. dispatch函数用于我们之后再次派发action
    2. getState函数考虑到我们之后的一些操作需要依赖原来的状态,用于让我们可以获取之前的一些状态;

ReduxToolkit

  1. Redux Toolkit 是官方推荐的编写 Redux 逻辑的方法。
    1. 在前面我们学习Redux的时候应该已经发现,redux的编写逻辑过于的繁琐和麻烦
    2. 并且代码通常分拆在多个文件中(虽然也可以放到一个文件管理,但是代码量过多,不利于管理)
    3. Redux Toolkit包旨在成为编写Redux逻辑的标准方式,从而解决上面提到的问题;
    4. 在很多地方为了称呼方便,也将之称为“RTK”;
  2. 安装Redux Toolkit:npm install @reduxjs/toolkit react-redux
  3. Redux Toolkit的核心API主要是如下几个
    1. configureStore:包装createStore以提供简化的配置选项和良好的默认值。它可以自动组合你的 slice reducer,添加你提供的任何 Redux 中间件,redux-thunk默认包含,并启用 Redux DevTools Extension。
    2. createSlice:接受reducer函数的对象、切片名称和初始状态值,并自动生成切片reducer,并带有相应的actions。
    3. createAsyncThunk: 接受一个动作类型字符串和一个返回承诺的函数,并生成一个pending/fulfilled/rejected基于该承诺分派动作类型的 thunk

configureStore

  1. 用于创建store对象,常见参数如下:
  2. reducer,将slice中的reducer可以组成一个对象传入此处;
  3. middleware:可以使用参数,传入其他的中间件(自行了解);
  4. devTools:是否配置devTools工具,默认为true;

createSlice

  1. 通过createSlice创建一个slice
  2. createSlice主要包含如下几个参数:
  3. name:用户标记slice的名词,
  4. initialState:初始化值,第一次初始化时的值;
  5. reducers:相当于之前的reducer函数
    1. 对象类型,并且可以添加很多的函数;
    2. 函数类似于redux原来reducer中的一个case语句;
    3. 函数的参数:
      1. 参数一:state
      2. 参数二:调用这个action时,传递的action参数;
  6. createSlice返回值是一个对象,包含所有的actions;

举例

  1. 项目入口index.js

     import React from 'react';
     import ReactDOM from 'react-dom/client';
     import { Provider } from "react-redux"
     import App from './App';
     import store from './store';
        
     const root = ReactDOM.createRoot(document.getElementById('root'));
     root.render(
         <Provider store={store}>
             <App />
         </Provider>
     );
    
  2. APP.js

     import React, { PureComponent } from 'react'
     import { connect } from "react-redux"
     import Profile from './pages/Profile'
     import Home from './pages/Home'
     import "./style.css"
        
     export class App extends PureComponent {
       render() {
         const { counter } = this.props
        
         return (
           <div>
             <h2>App Counter: {counter}</h2>
             <div className='pages'>
                 <Home/>
               <Profile/>
             </div>
           </div>
         )
       }
     }
        
     const mapStateToProps = (state) => ({
       counter: state.counter.counter
     })
        
     export default connect(mapStateToProps)(App)
    
  3. store文件夹

     //index.js
     import { configureStore } from "@reduxjs/toolkit"
     import counterReducer from "./features/counter"
        
     const store = configureStore({
       reducer: {
         counter: counterReducer
       }
     })
     export default store
        
     //./features/counter.js
     import { createSlice } from "@reduxjs/toolkit"
     const counterSlice = createSlice({
       name: "counter",
       initialState: {
         counter: 888
       },
       reducers: {
         //函数有2个参数,一个是state,一个是aciton,aciton有2个参数一个是type一个是payload,这里直接解构为payload
         addNumber(state, { payload }) {
           state.counter = state.counter + payload
         },
         subNumber(state, { payload }) {
           state.counter = state.counter - payload
         }
       }
     })
        
     export const { addNumber, subNumber } = counterSlice.actions
     export default counterSlice.reducer
    
  4. Profile.jsx

     import React, { PureComponent } from 'react'
     import { connect } from 'react-redux'
     import { subNumber } from '../store/features/counter'
        
     export class Profile extends PureComponent {
        
       subNumber(num) {
         this.props.subNumber(num)
       }
        
       render() {
         const { counter} = this.props
        
         return (
           <div>
             <h2>Page Counter: {counter}</h2>
             <button onClick={e => this.subNumber(5)}>-5</button>
             <button onClick={e => this.subNumber(8)}>-8</button>
           </div>
         )
       }
     }
        
     const mapStateToProps = (state) => ({
       counter: state.counter.counter
     })
        
     const mapDispatchToProps = (dispatch) => ({
       subNumber(num) {
         dispatch(subNumber(num))
       }
     })
     export default connect(mapStateToProps, mapDispatchToProps)(Profile)
    

Redux Toolkit的异步操作

  1. 在之前的开发中,我们通过redux-thunk中间件让dispatch中可以进行异步操作
  2. Redux Toolkit默认已经给我们继承了Thunk相关的功能:createAsyncThunk
  3. 当createAsyncThunk创建出来的action被dispatch时,会存在三种状态:
    1. pending:action被发出,但是还没有最终的结果;
    2. fulfilled:获取到最终的结果(有返回值的结果)
    3. rejected:执行过程中有错误或者抛出了异常;
  4. 可以在createSlice的entraReducer中监听这些结果

举例使用

  1. Home.jsx 在该页面进行触发网络请求

     import React, { PureComponent } from 'react'
     import { connect } from "react-redux"
     import { addNumber } from '../store/features/counter'
     import { fetchHomeMultidataAction } from '../store/features/home'
        
     export class Home extends PureComponent {
       componentDidMount() {
          
         //出发网络请求数据
         this.props.fetchHomeMultidata()
       }
        
       addNumber(num) {
         this.props.addNumber(num)
       }
        
       render() {
         const { counter } = this.props
        
         return (
           <div>
             <h2>Home Counter: {counter}</h2>
             <button onClick={e => this.addNumber(5)}>+5</button>
             <button onClick={e => this.addNumber(8)}>+8</button>
             <button onClick={e => this.addNumber(18)}>+18</button>
           </div>
         )
       }
     }
        
     const mapStateToProps = (state) => ({
       counter: state.counter.counter
     })
        
     const mapDispatchToProps = (dispatch) => ({
       addNumber(num) {
         dispatch(addNumber(num))
       },
       fetchHomeMultidata() {
         dispatch(fetchHomeMultidataAction({name: "why", age: 18}))
       }
     })
     export default connect(mapStateToProps, mapDispatchToProps)(Home)
    
  2. 在store中添加对一个的reducer

     // store/features/home.js
     import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
     import axios from 'axios'
        
     export const fetchHomeMultidataAction = createAsyncThunk(
       "fetch/homemultidata", 
       async (extraInfo, { dispatch, getState }) => {
         // console.log(extraInfo, dispatch, getState)
         // 1.发送网络请求, 获取数据
         const res = await axios.get("http://123.207.32.32:8000/home/multidata")
         return res.data
     })
        
     const homeSlice = createSlice({
       name: "home",
       initialState: {
         banners: [],
         recommends: []
       },
       reducers: {
         changeBanners(state, { payload }) {
           state.banners = payload
         },
            
         changeRecommends(state, { payload }) {
           state.recommends = payload
         }
       },
       //监听createAsyncThunk的返回过程
       extraReducers: {
          [fetchHomeMultidataAction.pending](state, action) {
            console.log("fetchHomeMultidataAction pending")
          },
          //拿到返回结果修改state
          [fetchHomeMultidataAction.fulfilled](state, { payload }) {
            state.banners = payload.data.banner.list
            state.recommends = payload.data.recommend.list
          },
           [fetchHomeMultidataAction.rejected](state, action) {
            console.log("fetchHomeMultidataAction rejected")
          }
        }
     })
        
     export const { changeBanners, changeRecommends } = homeSlice.actions
     export default homeSlice.reducer
    
     // 将homeReducer添加给store
     //store/index.js
     import { configureStore } from "@reduxjs/toolkit"
     import counterReducer from "./features/counter"
     import homeReducer from "./features/home"
        
     const store = configureStore({
       reducer: {
         counter: counterReducer,
         //新增homeReducer
         home: homeReducer
       }
     })
        
     export default store
    
  3. Profile.jsx展示数据

     import React, { PureComponent } from 'react'
     import { connect } from 'react-redux'
     import { subNumber } from '../store/features/counter'
        
     export class Profile extends PureComponent {
        
       subNumber(num) {
         this.props.subNumber(num)
       }
        
       render() {
         const { counter, banners, recommends } = this.props
        
         return (
           <div>
             <h2>Page Counter: {counter}</h2>
             <button onClick={e => this.subNumber(5)}>-5</button>
             <button onClick={e => this.subNumber(8)}>-8</button>
        
             <div className='banner'>
               <h2>轮播图展示</h2>
               <ul>
                 {
                   banners.map((item, index) => {
                     return <li key={index}>{item.title}</li>
                   })
                 }
               </ul>
             </div>
             <div className='recommend'>
               <h2>推荐的展示</h2>
               <ul>
                 {
                   recommends.map((item, index) => {
                     return <li key={index}>{item.title}</li>
                   })
                 }
               </ul>
             </div>
           </div>
         )
       }
     }
        
     const mapStateToProps = (state) => ({
       counter: state.counter.counter,
       banners: state.home.banners,
       recommends: state.home.recommends
     })
        
     const mapDispatchToProps = (dispatch) => ({
       subNumber(num) {
         dispatch(subNumber(num))
       }
     })
        
     export default connect(mapStateToProps, mapDispatchToProps)(Profile)
    

React中的state如何管理

  1. 三种状态管理方式:
    1. 组件中自己的state管理;
    2. Context数据的共享状态;
    3. Redux管理应用状态;
  2. 项目中采用的state管理方案:
    1. UI相关的组件内部可以维护的状态,在组件内部自己来维护;
    2. 大部分需要共享的状态,都交给redux来管理和维护
    3. 从服务器请求的数据(包括请求的操作),交给redux来维护;
Table of Contents