zoukankan      html  css  js  c++  java
  • 在react中使用redux

    写在前面

      在react中使用redux一直是一大痛点,redux 过于复杂 所以后来出现了mobx,当然今天不说mobx,今天说下redux(自以为很复杂的redux)。

             redux的基本用法就是:用户发出 Action,Reducer 函数算出新的 State,View 重新渲染。但是现在有一个问题就是,异步操作怎么办?Action 发出以后,Reducer 立即算出 State,这叫做同步;Action 发出以后,过一段时间再执行 Reducer,这就是异步。

             怎么才能 Reducer 在异步操作结束后自动执行呢?这就要用到新的工具:中间件(middleware)。本次用到的中间件有redux-thunk,redux-logger

             

    1. 安装四个npm包

      npm install --save redux react-redux redux-thunk
      npm install --save-dev redux-logger

      redux 和 react-redux 是必须的 redux-thunk可以帮你实现异步action。redux-logger可以实现监测redux的变化

    2. 文件结构

      然后我们在详细介绍一下每个文件所做的事情

    3. actions.js

      export const SET_PAGE_TITLE = "SET_PAGE_TITLE";
      export const SET_INFO_LIST = "SET_INFO_LIST";
      
      
      export function setPageTitle(data){
          return {type: SET_PAGE_TITLE, data: data}
      }
      
      export function setInfoList (data) {
        return (dispatch, getState) => {
          // 使用fetch实现异步请求
          // 请求发起前可以先dispatch一个加载开始状态
          // 例如 dispatch({ type: SET_LOADING_TYPE, data: "loading" })
          window.fetch('/api/getInfoList', {
              method: 'GET',
              headers: {
                  'Content-Type': 'application/json'
              }
          }).then(res => {
              return res.json()
          }).then(data => {
              let { code, data } = data
              if (code === 0) {
                  dispatch({ type: SET_INFO_LIST, data: data })
              }
              // 请求结束可以dispatch一个加载结束状态
              // 例如 dispatch({ type: SET_LOADING_TYPE, data: "loaded" })
              // 还可以区分一下成功或者失败
          })
        }
      }
      

        可以看出第一个action 是直接返回了一个action:{type: SET_PAGE_TITLE, data: data} ,而第二个则返回了一个函数,这个函数接受两个参数 dispatch 与 getState  , dispatch可以在异步加载完成以后发出一个action。在不使用redux-thunk这个中间件的时候dispatch接受的只能是一个action , 使用这个中间件就可以接受上文所说的参数,也就实现了Reducer 在异步操作结束后自动执行。

    4. reducers.js

      // reducers.js
      
      // combineReducers 工具函数,用于组织多个reducer,并返回reducer集合
      import {combineReducers} from 'redux'
      import defaultState from './state'
      import {SET_PAGE_TITLE,SET_INFO_LIST} from './actions'
      
      
      //一个reducer 就是一个函数
      function pageTitle ( state = defaultState.pageTitle, action){
          // 不同的action 有不同的处理逻辑
          switch (action.type) {
              case SET_PAGE_TITLE:
                  return action.data
              default:
                  return state
          }
      }
      
      function infoList (state = defaultState.infoList, action){
          switch (action.type) {
              case SET_INFO_LIST:
                  return action.data
              default:
                  return state
          }
      }
      
      export default combineReducers({
          pageTitle,
          infoList
      })
    5. state.js

      /**
          此文件存放state默认值
          同步数据:pageTitle
          异步数据:infoList(将来用异步接口获取)
       */
      
      export default {
          pageTitle:"首页",
          infoList:[]
      }
      

        

    6. index.js

      // index.js
      
      // applyMiddleware: redux通过该函数来使用中间件
      // createStore: 用于创建store实例
      import { applyMiddleware, createStore } from 'redux'
      
      // 中间件,作用:如果不使用该中间件,当我们dispatch一个action时,需要给dispatch函数传入action对象;但如果我们使用了这个中间件,那么就可以传入一个函数,这个函数接收两个参数:dispatch和getState。这个dispatch可以在将来的异步请求完成后使用,对于异步action很有用
      import thunk from 'redux-thunk'
      import logger from 'redux-logger'
      
      // 引入reducer
      import reducers from './reducers.js'
      
      // 创建store实例 第一个参数是reducer集合(reducers),第二个参数初始化的store(initialState),第三个参数是applyMiddleware函数,来使用中间件 ,因为只在reducer里面初始化了值,所以这里并没有传入初始化store的值
      let store = createStore(
        reducers,
        applyMiddleware(thunk,logger)
      )
      
      export default store
      

        

    7. 入口文件

      import React from 'react';
      import ReactDOM from 'react-dom';
      import {BrowserRouter as Router,Route} from "react-router-dom";
      import {Provider} from "react-redux";
      import store from './store'
      import App from './App'
      import * as serviceWorker from './serviceWorker';
      
      
      ReactDOM.render(
          <Provider store={store}>
              <Router >
                  <Route component={App} />
              </Router>
          </Provider>
      , document.getElementById('root'));
      
      // If you want your app to work offline and load faster, you can change
      // unregister() to register() below. Note this comes with some pitfalls.
      // Learn more about service workers: http://bit.ly/CRA-PWA
      serviceWorker.unregister();
      

        

    8. test.js

      // Test.jsx
      
      import React, { Component } from 'react'
      import {Route,Link} from 'react-router-dom'
      // connect方法的作用:将额外的props传递给组件,并返回新的组件,组件在该过程中不会受到影响
      import { connect } from 'react-redux'
      
      // 引入action
      import { setPageTitle, setInfoList } from '../store/actions.js'
      
      class Test extends Component {
        constructor(props) {
          super(props)
          this.state = {}
        }
      
        componentDidMount () {
          let { setPageTitle, setInfoList } = this.props
          
          // 触发setPageTitle action
          setPageTitle('新的标题')
          
          // 触发setInfoList action
          setInfoList([{data:1}])
        }
      
        render () {
          // 从props中解构store
          let { pageTitle, infoList } = this.props
          
          // 使用store
          return (
            <div>
              <div>
                <Link to="/courses/ii">Courses</Link>
              </div>
              <h1>{pageTitle}</h1>
              {
                  infoList.length > 0 ? (
                      <ul>
                          {
                              infoList.map((item, index) => {
                                  return <li key={index}>{item.data}</li>
                              })
                          }
                      </ul>
                  ):null
              }
            </div>
          )
        }
      }
      
      // mapStateToProps:将state映射到组件的props中
      const mapStateToProps = (state) => {
        return {
          pageTitle: state.pageTitle,
          infoList: state.infoList
        }
      }
      
      // mapDispatchToProps:将dispatch映射到组件的props中
      const mapDispatchToProps = (dispatch, ownProps) => {
        return {
          setPageTitle (data) {
              // 如果不懂这里的逻辑可查看前面对redux-thunk的介绍
              dispatch(setPageTitle(data))
              // 执行setPageTitle会返回一个函数
              // 这正是redux-thunk的所用之处:异步action
              // 上行代码相当于
              /*dispatch((dispatch, getState) => {
                  dispatch({ type: 'SET_PAGE_TITLE', data: data })
              )*/
          },
          setInfoList (data) {
              dispatch(setInfoList(data))
          }
        }
      }
      
      export default connect(mapStateToProps, mapDispatchToProps)(Test)
      

        

      代码的重点在connect函数。这个函数也是由react-redux提供的。使用它可以包装普通的展示组件(这里的Test——只负责展示数据),然后返回一个容器组件。connect函数通过第一个参数让展示组件订阅了来自store的数据;通过第二个参数让展示组件默认可以dispatch各种action。

     applyMiddlewares()

      applyMiddlewares是redux的原生方法,作用是将所有中间件组成一个数组,依次执行。

      要注意的是中间件为顺序有要求,具体可以查看你下载的npm包介绍。

      本次使用的redux-logger 必须放最后,不然可能监测不到正确的store

      

  • 相关阅读:
    3-剑指Offer: 连续子数组的最大和
    2-剑指offer: 最小的K个数
    1-剑指offer: 数组中出现次数超过一半的数字
    django中运行定时任务脚本
    django+sqlite进行web开发(二)
    django+sqlite3进行web开发(一)
    TL-WDN5200H无线usb网卡在Linux上的使用
    比较好用的C++11在线编译器
    MarkDown中如何加入上标和下标
    3. 卷积神经网络(CNN)
  • 原文地址:https://www.cnblogs.com/maopixin/p/9989236.html
Copyright © 2011-2022 走看看