Redux 是React生态中重要的组成部分。很多人都说,简单的应用可以不用此工具。但是我个人认为,中小型应用使用的话,可以使文件结构更加规范,代码可读性更强。因为React提出将展示组件与容器组件分离的思想,所以降低了React 与Redux之间的耦合度。
我个人粗浅的理解是:
Store的角色是整个应用的数据存储中心,集中大部分页面需要的状态数据;
ActionCreators ,view 层与data层的介质;
Reduce ,接收action并更新Store。
所以流程是 用户通过界面组件 触发ActionCreator,携带Store中的旧State与Action 流向Reducer,Reducer返回新的state,并更新界面。
所以也可以按照这个流程思想,来构建代码的结构了。
上图实现的就是输入输出的东西。输入框内输入一些内容,confirm后,label显示相应内容。
最开始
先安装几个库
npm install --save prop-types
npm install --save react-redux
npm install --save redux
1、首先构造界面
component/AddName.js
-这是一个纯React代码 ,结构清晰。
//component/AddName.js
import React, { Component } from 'react';
import PropTypes from 'prop-types'
class AddName extends Component {
//声明属性
static propTypes = {
lastname:PropTypes.string.isRequired,
addNameCreater:PropTypes.func.isRequired,
lastage:PropTypes.number.isRequired,
addAgeCreater:PropTypes.func.isRequired,
addNameAsync:PropTypes.func.isRequired
}
//点击事件
handlerFunc = () =>{
const inputName = this.refs.inputValueTest.value;
this.props.addNameCreater(inputName);
}
handlerAgeFunc = () =>{
const inputage = this.refs.inputValueAge.value;
this.props.addAgeCreater(inputage);
}
handlerAsyncFunc = () =>{
const inputName = this.refs.inputValueTest.value;
this.props.addNameAsync(inputName);
}
//渲染界面
render() {
const {lastname,lastage} = this.props;
return (
<div>
<header className="App-header">
<h1 className="App-title">Welcome to React</h1>
</header>
<label> {lastname} </label><br/>
<input ref="inputValueTest" /><br/>
<button onClick={this.handlerFunc}>confirm</button><br/>
<label> {lastage} </label><br/>
<input ref="inputValueAge" />
<button onClick={this.handlerAgeFunc}>confirm</button><br/>
<button onClick={this.handlerAsyncFunc}>Async Confirm</button><br/>
</div>
);
}
}
export default AddName;
2、然后,根据流程图,我们需要定义一些操作了,也就是ActionCreator.它会传达用户的操作信息以及一些数据
先定义一些常量供我们使用,这里就两种操作,一是添加名字,二是添加年龄,实际都一样。为了后面实现reducer的合并强行写了俩。这写常量一般都定义在actionTpye文件中
Redux/actionType.js
export const ADDNAME = 'ADDNAME'
export const ADDAGE = 'ADDAGE'
接着就是写ActionCreator ,定义了一些操作类型,告诉store自己是干什么的,需要什么样的数据。
Redux/actions.js
import { ADDNAME,ADDAGE } from "./action-type";
//包含所有的action creator
export const addNameCreater = (name) =>({type:ADDNAME,data:name})
export const addAgeCreater = (age) => ({type:ADDAGE,data:age})
export const addNameAsync = (name) =>{
return dispatch =>{
setTimeout(()=>{
dispatch(addNameCreater(name))
},2000);
}
}
3、Reducer 会接收到action的信息。将会进行状态(数据)的处理,相当于react中的setState()的功能。如果有多个reducer ,可以使用combineReducers方法将其合并,并暴露出去。
Redux/reducer.js
//包含n个reducer函数的模块
import {ADDNAME, ADDAGE} from './action-type'
import {combineReducers} from 'redux'
function addName(state='initRedux',action){ //形参默认值
switch(action.type){
case ADDNAME:
return action.data
default:
return state
}
}
function addAge(state=0,action){
switch(action.type){
case ADDAGE:
return action.data
default:
return state
}
}
export const finalReducer = combineReducers({
addName,addAge
})
其中state='initRedux' 、state=0 相当于我们在React组件内部初始化state.
4、一切操作还是基于Store 的。类似于中央集权。所以还要把Store建立出来
Redux/store.js
import {createStore,applyMiddleware} from 'redux'
import {finalReducer } from './reducers'
import thunk from 'redux-thunk'
//生成store对象
const store = createStore(finalReducer,applyMiddleware(thunk));//内部会第一次调用reducer函数,得到初始state
export default store
因为reducer会更新Store中的状态(数据),所以需要引入reducer ,并创建store.
到此,流程图到这里就走完了。不过2、3、4都是redux中负责接管React 状态的功能。1是React负责展示的组件。两者并没啥关系。既然有了展示组件,接下来就要有容器组件了。也就是能够将React与redux相关联的一个组件。
5、构建容器组件
containers/App.js
import React from 'react'
import {connect} from 'react-redux'
import {addNameCreater,addAgeCreater,addNameAsync} from '../redux/actions'
import AddName from '../component/AddName'
export default connect(
state => ({
lastname:state.addName,
lastage:state.addAge
}),
{addNameCreater,addAgeCreater,addNameAsync}
)(AddName)
这里用到了react- redux中的connect 。可以将React与redux关联起来。AddName就是第一步写的组件名。state中关联了React中的属性。这里面涉及到两个API,到第二章详细描述。
6、添加store
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux'
import App from './containers/App'
import store from './redux/store'
ReactDOM.render((
//使用Provider 组件将APP主组件包裹住,这样内部组件都有Store种提供的属性。
<Provider store={store}>
<App/>
</Provider>
), document.getElementById('root'));
这样就OK了。
上图是主要的文件结构,
-redux 集中管理状态(数据)
-component 专注于React 展示组件部分
-containers 集中处理React与redux交互的部分
此外,redux还可以处理一些异步请求。这样的话。可以做到data 和view 的管理分离,增强了工程结构的可读性与可维护性。