一个被写烂的redux计数小例子

简单准备

  • 通过create-react-app快速搭建react项目
  • 安装依赖npm install redux react-redux redux-thunk --save (redux-thunk是处理异步数据流的中间件)
  • 更改,新建项目目录

  • 效果图

Demo开始

编写redux相关内容

action

export const Increment = 'increment'
export const Decrement = 'decrement'
/*action creator action构造函数*/
export const increment = (counterIndex) => {
  type:Increment,
  counterIndex
}
export const decrement = (counterIndex) => ({
  type: Decrement,
  counterIndex
})
复制代码

Action 本质上是 JavaScript 普通对象。action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作,但是这样有多少action就需要写多少action,所以这里需要action creator, 这个action构造函数返回一个js对象,当然这里在处理异步数据的时候需要返回一个函数,此时需要用到中间件。

reducer

import { Increment, Decrement } from '../Action'
export default (state,action) => {
  const {counterIndex} = action
  switch (action.type) {
    case Increment:
    return {...state, [counterIndex]:state[counterIndex]+1}
    case Decrement:
    return {...state, [counterIndex]:state[counterIndex]-1}
    default:
    return state
  }
}
复制代码

reducer具体定义可以看redux自述中的定义,由于demo太简单,拆分合并reducer大家自己看吧,这里主要介绍redux在react中的工作流程。 这里要注意reducer是个纯函数,不能更改state,这里返回的新state可以使用Object.assign 以及 es6的对象扩展符。

store

import {applyMiddleware, createStore} from 'redux'
import thunk from 'redux-thunk'
import reducer from '../Reducer'
const initValue={
    'First':1,
    'Second':5,
    'Third':6
}
const store=createStore(reducer,initValue)
export default store
复制代码

createStorestore 可以接受一个初始的state,这里可以设置服务端同构应用的初始化props。 至此redux的相关就结束,下面写ui组件。

编写UI组件

如果不用react-redux自动生成容器组件,组件划分就要有容器组件和展示的区分,我理解的展示组件就是没有自己的state,只接受 props决定UI该如何展示,所有的逻辑都在容器组件进行,由于react-redux,我们不需要自己写容器组件

Counter

    import React, { Component } from 'react';
    import {increment, decrement} from '../Redux/Action'
    import {connect} from 'react-redux'
    import '../style/App.css';
    const buttonMargin= {
      margin: "20px"
    }
    
    function Counter({index, Increment, Decrement, value}){
      return (
                <div>
                   <button style={buttonMargin} onClick={Increment}>+</button>
                   <button style={buttonMargin} onClick={Decrement}>-</button>
                   <span>{index} count :{value}</span>
                </div>
      )
    }
    function mapStateToProps(state,ownProps){
      return{
        value:state[ownProps.index]
      }
    }
    function mapDispatchToProps(dispatch, ownProps){
      return{
        Increment:() => {
          dispatch(increment(ownProps.index))
        },
        Decrement:() => {
          dispatch(decrement(ownProps.index))
        }
      }
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Counter);
复制代码
  • react-redux提供方法connect()和组件,这里说下connect(),引用阮一峰大神的总结: connect方法接受两个参数:mapStateToProps和mapDispatchToProps。它们定义了 UI 组件的业务逻辑。前者负责输入逻辑,即将state映射到 UI 组件的参数(props),后者负责输出逻辑,即将用户对 UI 组件的操作映射成 Action。
  • mapStateToProps:作为函数,mapStateToProps执行后应该返回一个对象,里面的每一个键值对就是一个映射。 接受两个参数state,ownProps,state 。state更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染,ownProps代表容器组件的props对象,如果容器组件的参数发生变化,也会引发 UI 组件重新渲染,例如上面个的计数;
  • mapDispatchToProps是connect函数的第二个参数,用来建立 UI 组件的参数到store.dispatch方法的映射。也就是说,它定义了哪些用户的操作应该当作 Action,传给 Store。它可以是一个函数,也可以是一个对象

Panel

import React, { Component } from 'react'
import Counter from './Counter.js'
const style = {
    margin: "20px"
}

class Panel extends Component {
    render() {
        return (
            <div style={style}>
                <Counter index="First" />
                <Counter index="Second"/>
                <Counter index="Third" />
                <hr/>
            </div>
        )
    }
}
复制代码

export default Panel

这里就是个list。

index.js(入口文件)

import React from 'react';
import ReactDOM from 'react-dom';
import './style/index.css';
import Panel from './Component/Panel';
import {Provider} from 'react-redux';
import store from './Redux/Store/store.js'
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(
       <Provider store={store}>
         <Panel/>
       </Provider>,<pre>
   document.getElementById('root')
  );
registerServiceWorker();
复制代码

React-Redux 提供Provider组件,可以让容器组件拿到state,避免一层层向下传,原理是context,其实也很好理解,vue有个bus。 至此一个同步的redux处理数据的demo就完成了,下面来说异步。

异步

vuex 提交的是Mutation(有点像git) 这个东西是同步, 而它有action 这里可以同步异步,但redux并没有,所以这里就有了中间件的出现,用于解决异步action,中间件有几种常用的,这里只简单写下redux-thunk。 action creator 原则是返回一个js对象,异步在这里处理,返回的是一个函数,这就需要中间件的处理。 修改这两处:

action:

export const Increment = 'increment'
export const Decrement = 'decrement'

export const increment = (counterIndex) => {
   return dispatch => {
		let asyncAct = {
			type:Increment,
                        counterIndex
		}
		setTimeout(()=>{ //两秒钟之后再发送action
			dispatch(asyncAct);
		}, 2000)
	}
 }
export const decrement = (counterIndex) => ({
   type: Decrement,
   counterIndex
 })
复制代码

store:

import {applyMiddleware, createStore} from 'redux'
import thunk from 'redux-thunk'
import reducer from '../Reducer'
const initValue={
    'First':1,
    'Second':5,
    'Third':6
}
const store=createStore(reducer,initValue,applyMiddleware(thunk))
//使用中间件的写法applyMiddleware,如果多个,注意里面中间件的顺序
export default store
复制代码

简单的延时2s再计数完成啦。

猜你喜欢

转载自juejin.im/post/5bfceebe51882516cd70ba97