前言
前幾天,我在博文
【前端】一步一步使用webpack+react+scss腳手架重構項目中搭建了一個react開發環境。然而在實際的開發過程中,或者是在對源碼的了解中,感受到react中用的最多的,就是redux了,于是打開文檔學習了一番。在這裡做一些記錄。
redux概念
redux是什麼?它是用來管理狀态的。在react開發中,我們經常會遇到一種情況,元件與父元件之間的通信,元件與元件之間的通信,
其中元件與父元件的通信通過props來完成。
/***********parent****************/
<Number
value={this.state.number}
/>
/***********number****************/
<div >{this.props.value}</div>
number内部使用props擷取父元件自己的state,通過setState更改父元件的state.number可以實作number元件的實時更新。
那麼元件與元件之間的通信呢?例如我們有a,b兩個元件,現在a要給b轉發一個激活狀态active,一般思路是,在同一個父元件下,使用props傳遞回調函數的方式。
/*********元件 a**********/
class A{
.....
changeActive(){
this.props.changebActive();
}
render(){
return <button onClick={this.changeActive}></button>
}
}
/*********元件 b**********/
class B{
render(){
return <div>狀态:{this.props.active}</div>
}
}
/*********元件 parent**********/
class parent{
......
changebActive(){
this.setState({
active:"開啟"
})
}
render(){
return <div>
<A
changebActive={this.changebActive.bind(this)}
/>
<B
active={this.state.active}
/>
</div>
}
}
通過A點選調用到parent的 changebActive方法,設定state更新b,這種方式非常容易使項目變得不可預測,并且state管理複雜,沒錯,redux很大程度就是用來解決這個問題的,它在react中的思想是:
将元件狀态統一放到同一個超級父元件,再由這個超級父元件用更專業的方法分發props給所有的子元件,無論嵌套多少層。由超級父元件統一管理應用中所有的state。
---這就是redux。無論api名詞如何晦澀難懂,它的核心思想是在開發中浮現的。
redux的API
一、所有的狀态,儲存在一個對象裡面。
所有的狀态都儲存在一個對象裡面,redux基本三大原則之一,單一資料源,一個應用所有的狀态被儲存在一個對象裡,這個對象通過store管理,想象一下,整個頁面的狀态被存儲在一個對象裡面,其實類似一個配置檔案,你可以從伺服器讀取,可以從任何地方改變。view則是同步的,這看起來更精煉不是麼。
二、store
Store 就是儲存狀态資料對象的地方,你可以把它看成一個容器。整個應用隻能有一個 Store。
Redux 提供
createStore
這個函數,用來生成 Store。createStore傳入了一個函數這個函數将接收到兩個參數,一個state,一個action,action就是由子元件發出的更改請求,state就是那個單一的state對象。
import { createStore } from 'redux';
const store = createStore(fn);
三、action
發起狀态改變的起點是action,由子元件發出action,子元件通過props調用回調函數,通知父元件發出action。
觸發:
store.dispatch(action);
四、store.dispatch
這個方法就是發出action的方法,一般傳入action,調用這個方法之後,會觸發在createStore中傳入的函數。
五、store.getState
它用來擷取目前的state對象
六、reducer
這個就是createStore中傳入的函數的名詞解釋,這個函數的執行必須傳回一個新的state:
export default (state={number:0},action)=>{//每次調用都會傳入state和目前通知的action
switch(action.type){
case "NUMBER_ADD": //發過來的action如果是NUMBER_ADD 就傳回number++
state.number++;
break;
case "NUMBER_LESS":
state.number--;
break;
}
return Object.assign({},state); //必須傳回一個新的state ,可以使用assign合并
}
注意這裡用了es6,給state添加了一個預設值,{number:0}。
六、store.subscribe()
Store 允許使用
store.subscribe
方法設定監聽函數,一旦 State 發生變化,就自動執行這個函數。
import { createStore } from 'redux';
const store = createStore(reducer);
store.subscribe(render);
比如上面我在生成store傳入reducer函數之後,使用store.subscribe()設定監聽函數為render,則每次state改變了,就會執行render函數,重新整理視圖。
概念名詞太多,不如實踐
實踐一個number輸入框的加減元件,你就能大概知道redux究竟是怎麼工作的。
一、準備
首先你需要搭建一個react的開發環境,需要一個index.html 輸出目錄等。詳見我的另一篇博文:
。
然後你需要一定的react開發實踐,React有props和state兩個屬性: props意味着父元件分發下來的屬性,state意味着元件内部可以自行管理的狀态,并且整個React沒有資料向上回溯的能力,也就是說資料隻能單向向下分發,或者自行内部消化。
了解這個是了解React和Redux的前提。
你需要npm安裝redux:
num install redux react-redux --save-dev
二、代碼
1.number.js
import React,{Component} from "react";
const propTypes = {
add:React.PropTypes.func.isRequired,
less:React.PropTypes.func.isRequired,
value:React.PropTypes.object.isRequired
}
class Number extends Component{
add(){
this.props.add({type:"NUMBER_ADD"}) //調用app.js中傳過來的箭頭函數,傳入了type為NUMBER_ADD的action
}
less(){
this.props.less({type:"NUMBER_LESS"})
}
render(){
return <div>
<input type="text" value={this.props.value.number}/>
<button onClick={this.add.bind(this)}>
+
</button>
<button onClick={this.less.bind(this)}>
-
</button>
</div>
}
}
Number.propTypes = propTypes;
export {Number};
注意那兩個click回調,發出了action,以及那個this.props.value.number的引用,props傳入了state,擷取了state.number
2.app.js
import React from "react";
import ReactDOM from "react-dom";
import {createStore} from "redux"; //導入createStore
import {Number} from "./number.js";
import reducers from "./reducers.js";
const store = createStore(reducers); //生成store
const content = document.querySelector(".content");
const render = ()=> ReactDOM.render(
<div>
<Number
value={store.getState()}
add={(action)=>store.dispatch(action)} //傳入一個函數,傳入發送過來的action,由reducers處理之後傳回state,
less={(action)=>store.dispatch(action)}
/>
</div>,
content
);
render();
store.subscribe(render); //在reducers處理之後,傳回了state,然後觸發了render,更新視圖
3.reducers.js
export default (state={number:0},action)=>{//每次調用都會傳入state和目前通知的action
switch(action.type){
case "NUMBER_ADD": //發過來的action如果是NUMBER_ADD 就傳回number++
state.number++;
break;
case "NUMBER_LESS":
state.number--;
break;
}
return Object.assign({},state); //必須傳回一個新的state ,可以使用assign合并
}
這就是createStore傳入的函數,當發出action,store會自動調用它傳入state,action 傳回了一個新的state.
Redux 的基本用法就介紹到這裡,下一篇介紹它的進階用法:中間件和異步操作。為什麼是下一篇?因為我也還沒學。
資源
阮一峰的教程 number——demo的github 知乎上大神對redux的易懂解讀--------------------------------
轉載必須在頁頭注明出處,此前多文章被轉載不署名,自重
========================================================
轉載請注明出處。