Redux 是React生態(tài)中重要的組成部分狐援。很多人都說(shuō)囊拜,簡(jiǎn)單的應(yīng)用可以不用此工具某筐。但是我個(gè)人認(rèn)為,中小型應(yīng)用使用的話艾疟,可以使文件結(jié)構(gòu)更加規(guī)范来吩,代碼可讀性更強(qiáng)。因?yàn)镽eact提出將展示組件與容器組件分離的思想蔽莱,所以降低了React 與Redux之間的耦合度弟疆。
我個(gè)人粗淺的理解是:
Store的角色是整個(gè)應(yīng)用的數(shù)據(jù)存儲(chǔ)中心怠苔,集中大部分頁(yè)面需要的狀態(tài)數(shù)據(jù);
ActionCreators ,view 層與data層的介質(zhì)仪糖;
Reduce 柑司,接收action并更新Store。
所以流程是 用戶通過(guò)界面組件 觸發(fā)ActionCreator锅劝,攜帶Store中的舊State與Action 流向Reducer,Reducer返回新的state攒驰,并更新界面。
所以也可以按照這個(gè)流程思想故爵,來(lái)構(gòu)建代碼的結(jié)構(gòu)了玻粪。
上圖實(shí)現(xiàn)的就是輸入輸出的東西。輸入框內(nèi)輸入一些內(nèi)容,confirm后劲室,label顯示相應(yīng)內(nèi)容伦仍。
最開始
先安裝幾個(gè)庫(kù)
npm install --save prop-types
npm install --save react-redux
npm install --save redux
1、首先構(gòu)造界面
component/AddName.js
-這是一個(gè)純React代碼 很洋,結(jié)構(gòu)清晰充蓝。
//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
}
//點(diǎn)擊事件
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、然后喉磁,根據(jù)流程圖谓苟,我們需要定義一些操作了,也就是ActionCreator.它會(huì)傳達(dá)用戶的操作信息以及一些數(shù)據(jù)
先定義一些常量供我們使用,這里就兩種操作线定,一是添加名字娜谊,二是添加年齡,實(shí)際都一樣斤讥。為了后面實(shí)現(xiàn)reducer的合并強(qiáng)行寫了倆纱皆。這寫常量一般都定義在actionTpye文件中
Redux/actionType.js
export const ADDNAME = 'ADDNAME'
export const ADDAGE = 'ADDAGE'
接著就是寫ActionCreator ,定義了一些操作類型芭商,告訴store自己是干什么的派草,需要什么樣的數(shù)據(jù)。
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 會(huì)接收到action的信息近迁。將會(huì)進(jìn)行狀態(tài)(數(shù)據(jù))的處理,相當(dāng)于react中的setState()的功能簸州。如果有多個(gè)reducer 鉴竭,可以使用combineReducers方法將其合并,并暴露出去岸浑。
Redux/reducer.js
//包含n個(gè)reducer函數(shù)的模塊
import {ADDNAME, ADDAGE} from './action-type'
import {combineReducers} from 'redux'
function addName(state='initRedux',action){ //形參默認(rèn)值
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 相當(dāng)于我們?cè)赗eact組件內(nèi)部初始化state.
4、一切操作還是基于Store 的矢洲。類似于中央集權(quán)璧眠。所以還要把Store建立出來(lái)
Redux/store.js
import {createStore,applyMiddleware} from 'redux'
import {finalReducer } from './reducers'
import thunk from 'redux-thunk'
//生成store對(duì)象
const store = createStore(finalReducer,applyMiddleware(thunk));//內(nèi)部會(huì)第一次調(diào)用reducer函數(shù),得到初始state
export default store
因?yàn)閞educer會(huì)更新Store中的狀態(tài)(數(shù)據(jù))读虏,所以需要引入reducer 责静,并創(chuàng)建store.
到此,流程圖到這里就走完了盖桥。不過(guò)2灾螃、3、4都是redux中負(fù)責(zé)接管React 狀態(tài)的功能揩徊。1是React負(fù)責(zé)展示的組件睦焕。兩者并沒(méi)啥關(guān)系藐握。既然有了展示組件,接下來(lái)就要有容器組件了垃喊。也就是能夠?qū)eact與redux相關(guān)聯(lián)的一個(gè)組件。
5袜炕、構(gòu)建容器組件
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關(guān)聯(lián)起來(lái)偎窘。AddName就是第一步寫的組件名乌助。state中關(guān)聯(lián)了React中的屬性。這里面涉及到兩個(gè)API陌知,到第二章詳細(xì)描述他托。
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主組件包裹住仆葡,這樣內(nèi)部組件都有Store種提供的屬性赏参。
<Provider store={store}>
<App/>
</Provider>
), document.getElementById('root'));
這樣就OK了。
上圖是主要的文件結(jié)構(gòu)沿盅,
-redux 集中管理狀態(tài)(數(shù)據(jù))
-component 專注于React 展示組件部分
-containers 集中處理React與redux交互的部分
此外把篓,redux還可以處理一些異步請(qǐng)求。這樣的話腰涧∪脱冢可以做到data 和view 的管理分離,增強(qiáng)了工程結(jié)構(gòu)的可讀性與可維護(hù)性窖铡。