简单准备
- 通过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对象,当然这里在处理异步数据的时候需要返回一个函数,此时需要用到中间件去改写dispatch。
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再计数完成啦。