時間:2016.4.7-17:24
做者:三月懶驢
入門配置文章:連接javascript
在你的項目下面加入redux / react-redux前端
npm install redux --save npm install react-redux --save
網上有不少關於Redux的解析了,我也不從抽象化去講解整個redux的做用,而發現講解Redux的編程化例子其實不多,因此在這裏用代碼來講明一下。什麼叫作redux,以及它的Action/reducer/storejava
看過我上一遍項目環境搭建的朋友應該有一個基本的項目目錄架構。react
主要寫代碼的仍是在app這個文件夾裏面,裏面的目錄分佈npm
- component -->放置組件的 - redux -->放置action && reducer - redux_lesson -->目前是放置用Provider打包出來的組件 - main.js -->程序入口
咱們如今要作一個很簡單的東西,用前端的話來講就是一個div標籤,裏面放置一個數字0,當咱們點擊這個div的時候,裏面的數字就遞增。這裏面咱們要進行一步就是,寫代碼前的思考。
如上所說,咱們的需求就是:點擊,數字遞增。那麼咱們的一些參數應該定義出來了。編程
我的簡單理解的state就是能夠反映到view上的可變數據,這裏咱們的state定義以下redux
state = {count:0}
一樣是我的理解:state是可變的,但不是隨便的可變,要改變它,就須要一把鑰匙去打開這道大門,而action就是這把鑰匙了
咱們把這個action定義成以下:segmentfault
increaseAction = {type:'increase'}
Action 本質上是 JavaScript普通對象。咱們約定,action內使用一個字符串類型的 type字段來表示將要執行的動做。多數狀況下,type 會被定義成字符串常量。架構
我的的胡亂理解:有了state,有了要改變state的鑰匙Action,那麼誰來進行改變state的操做?reducer就是這麼一個加工車間,你拿着原料(state)和鑰匙(Action)進去總車間,用鑰匙(Action)打開對應的生產線,生產出來新的產品(也是state)回去app
let reducer = (state={count:0},action)=>{ //這裏面傳遞進來兩個參數, //一個是咱們前面定義的state,若是木有傳入的話,就用{count:0} //一個是咱們前面定義的action,下面就要檢查它的type來肯定操做 let count = state.count switch(action.type){ //若是鑰匙插對了孔,咱們就返回進行了相應操做後的state對象 case 'increase': return {count:count+1} break //若是鑰匙都不對,就返回沒操做過的state default: return state } }
由於相對前面三個東西來講,store是在太容易理解了,引入官方的話:
Store 就是把它們聯繫到一塊兒的對象。Redux 應用只有一個單一的 store。當須要拆分處理數據的邏輯時,使用 reducer 組合 而不是建立多個 store。
其實上面的步驟咱們都把一個redux處理數據的相關工做作的差很少了,那麼接下來就是要真正的去寫成程序
文件位置: app/redux/action.js
export const increaseAction = {type:'increase'}
文件位置: app/redux/reudcer.js
let reducer = (state={count:0},action)=>{ let count = state.count switch(action.type){ case 'increase': return {count:count+1} break default: return state } } export default reducer
重要的事情:store只有一個!
文件位置: app/redux_lesson/lesson_0.js
'use strict' import React from 'react' import { createStore } from 'redux' import { Provider,connect } from 'react-redux' //這個index.js文件會在在下一步建立 import Index from '../component/index' import reducers from '../redux/reducer' //建立store let store = createStore(reducers) /* mapStateToProps你能夠理解成在下面connect的時候爲組件提供一個props,這個props的值是redux的state */ let mapStateToProps = (state) =>{ return {count:state.count} } //鏈接你的state和最外層的組件 let Content = connect(mapStateToProps)(Index) let {Component} = React //使用Provider來把新的App組件打包出來 class App extends Component{ render(){ return <Provider store={store}><Content /></Provider> } } export default App
在View裏面咱們會接受到兩個props。一個是在mapStateToProps生成的state,一個是store給咱們的dispatch,這是是一個函數,咱們用它的方法很簡單粗暴,往裏面傳入一個Action就好了,它接受了這個Action就會告訴reducer去執行。
文件位置: app/compoment/index.js
'use strict' import React from 'react' import { connect } from 'react-redux' //請注意這裏面引入了action import {increaseAction} from '../redux/action' let {Component,PropTypes} = React class Index extends Component{ //這一步是檢查傳入的各個prop類型是否正確 ProTypes = { count:PropTypes.number.isRequired, } constructor(props){ super(props) } handleClick(){ /* 這一步輸入this.props能夠看到,其實裏面有兩個東西 在下面的render裏面咱們用到了this.props.count這個 那麼這裏咱們要用到dispatch */ console.log(this.props) let {dispatch} = this.props //粗暴簡單的使用 dispatch(increaseAction) } render(){ let {count} = this.props return <div onClick = {this.handleClick.bind(this)} style={styles.circle}>{count}</div> } } //樣式文件,不用細看 let styles = { circle:{ width:'100px', height:'100px', position:'absolute', left:'50%', top:'50%', margin:'-50px 0 0 -5px', borderRadius:'50px', fontSize:'60px', color:'#545454', backgroundColor:'#fcfcfc', lineHeight:'100px', textAlign:'center', } } export default Index
要作一個點擊遞增就須要那麼多步驟是否是很煩惱?可是若是項目大起來以後,你想像這樣,你就能夠建立不一樣的鑰匙Action,再編寫不一樣的生產線reducer來修改各自的state,可是如上所作,咱們的邏輯代碼(點擊遞增)和View仍是捆綁在一塊兒(就是在組件裏面使用dispatch)這個方法是不可取的。因此下一步咱們就要進一步優化咱們的代碼
文件位置: app/redux_lesson/lesson_0.js
'use strict' import React from 'react' import { createStore } from 'redux' import { Provider,connect } from 'react-redux' import Index from '../component/index' import reducers from '../redux/reducer' /* 注意:這裏是新增的 相對原來,咱們在最外層打包這裏引入Action */ import {increaseAction} from '../redux/action' //建立store let store = createStore(reducers) /* mapStateToProps你能夠理解成在下面connect的時候提供一個state */ let mapStateToProps = (state) =>{ return {count:state.count} } /* 注意:這裏是新增的 mapDispatchToProps你能夠理解成在下面connect的時候提供一個放置好鑰匙的函數onIncreaseClick,直接調用就能夠去reducer修改state了 */ let mapDispatchToProps = (dispatch) =>{ return{onIncreaseClick:()=>dispatch(increaseAction)} } /* 注意:這裏是修改了的 鏈接你的state和最外層的組件 */ let Content = connect(mapStateToProps,mapDispatchToProps)(Index) let {Component} = React //使用Provider來把新的App組件打包出來 class App extends Component{ render(){ return <Provider store={store}><Content /></Provider> } } export default App
文件位置: app/compoment/index.js
'use strict' import React from 'react' import { connect } from 'react-redux' /* 注意:這裏是修改樂的 如今不用引入action了,由於前一步已經把鑰匙Action放到相應的函數中去,做爲props傳入組件裏面 */ //import {increaseAction} from '../redux/action' let {Component,PropTypes} = React class Index extends Component{ //這一步是檢查傳入的各個prop類型是否正確 ProTypes = { count:PropTypes.number.isRequired, onIncreaseClick:PropTypes.func.isRequired, } constructor(props){ super(props) } handleClick(){ /* 注意:這裏是修改過的 如今,咱們把打包好的,帶着鑰匙的函數進行調用 */ console.log(this.props) let {onIncreaseClick} = this.props onIncreaseClick() } render(){ let {count} = this.props return <div onClick = {this.handleClick.bind(this)} style={styles.circle}>{count}</div> } } //樣式文件,不用細看 ...(如下相同就略去)
redux其實不難理解,按照我我的理解的加工工廠模式:有一家大公司叫作store,裏面有工廠(reducer),公司(store)只有一家,但這家公司(store)能夠有不少工廠(reducer)。要進去工廠加工產品(state),就得帶上相應得鑰匙(Action),不一樣的鑰匙(Action)對應工廠中上不一樣的生產線(redecer裏面的switch函數),從而有不一樣的產出(改變以後的state)