Redux之旅-1
時(shí)間:2016.4.7-17:24
作者:三月懶驢
入門配置文章:鏈接
準(zhǔn)備
在你的項(xiàng)目下面加入redux / react-redux
npm install redux --save
npm install react-redux --save
入門小例子
網(wǎng)上有很多關(guān)于Redux的解析了,我也不從抽象化去講解整個(gè)redux的作用,而發(fā)現(xiàn)講解Redux的編程化例子其實(shí)很少,所以在這里用代碼來說明一下。什么叫做redux,以及它的Action/reducer/store
看過我上一遍項(xiàng)目環(huán)境搭建的朋友應(yīng)該有一個(gè)基本的項(xiàng)目目錄架構(gòu)。
主要寫代碼的還是在app這個(gè)文件夾里面,里面的目錄分布
- component -->放置組件的
- redux -->放置action && reducer
- redux_lesson -->目前是放置用Provider打包出來的組件
- main.js -->程序入口
代碼開始前的思考
我們現(xiàn)在要做一個(gè)很簡(jiǎn)單的東西,用前端的話來說就是一個(gè)div標(biāo)簽,里面放置一個(gè)數(shù)字0,當(dāng)我們點(diǎn)擊這個(gè)div的時(shí)候,里面的數(shù)字就遞增。這里面我們要進(jìn)行一步就是,寫代碼前的思考。
如上所說,我們的需求就是:點(diǎn)擊,數(shù)字遞增。那么我們的一些參數(shù)應(yīng)該定義出來了。
改變View的數(shù)據(jù)—state
個(gè)人簡(jiǎn)單理解的state就是可以反映到view上的可變數(shù)據(jù),這里我們的state定義如下
state = {count:0}
改變state的鑰匙—Action
同樣是個(gè)人理解:state是可變的,但不是隨便的可變,要改變它,就需要一把鑰匙去打開這道大門,而action就是這把鑰匙了
我們把這個(gè)action定義成如下:
increaseAction = {type:'increase'}
Action 本質(zhì)上是 JavaScript普通對(duì)象。我們約定,action內(nèi)使用一個(gè)字符串類型的 type字段來表示將要執(zhí)行的動(dòng)作。多數(shù)情況下,type 會(huì)被定義成字符串常量。
改變state的動(dòng)作—Reducer
個(gè)人的胡亂理解:有了state,有了要改變state的鑰匙Action,那么誰(shuí)來進(jìn)行改變state的操作?reducer就是這么一個(gè)加工車間,你拿著原料(state)和鑰匙(Action)進(jìn)去總車間,用鑰匙(Action)打開對(duì)應(yīng)的生產(chǎn)線,生產(chǎn)出來新的產(chǎn)品(也是state)回去
let reducer = (state={count:0},action)=>{
//這里面?zhèn)鬟f進(jìn)來兩個(gè)參數(shù),
//一個(gè)是我們前面定義的state,如果木有傳入的話,就用{count:0}
//一個(gè)是我們前面定義的action,下面就要檢查它的type來確定操作
let count = state.count
switch(action.type){
//如果鑰匙插對(duì)了孔,我們就返回進(jìn)行了相應(yīng)操作后的state對(duì)象
case 'increase':
return {count:count+1}
break
//如果鑰匙都不對(duì),就返回沒操作過的state
default:
return state
}
}
被我吃了的store
因?yàn)橄鄬?duì)前面三個(gè)東西來說,store是在太容易理解了,引入官方的話:
Store 就是把它們聯(lián)系到一起的對(duì)象。Redux 應(yīng)用只有一個(gè)單一的 store。當(dāng)需要拆分處理數(shù)據(jù)的邏輯時(shí),使用 reducer 組合 而不是創(chuàng)建多個(gè) store。
開始真正寫代碼了
其實(shí)上面的步驟我們都把一個(gè)redux處理數(shù)據(jù)的相關(guān)工作做的差不多了,那么接下來就是要真正的去寫成程序
創(chuàng)建action
文件位置: app/redux/action.js
export const increaseAction = {type:'increase'}
創(chuàng)建reducer
文件位置: 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,打包出新組件
重要的事情:store只有一個(gè)!
文件位置: app/redux_lesson/lesson_0.js
'use strict'
import React from 'react'
import { createStore } from 'redux'
import { Provider,connect } from 'react-redux'
//這個(gè)index.js文件會(huì)在在下一步創(chuàng)建
import Index from '../component/index'
import reducers from '../redux/reducer'
//創(chuàng)建store
let store = createStore(reducers)
/*
mapStateToProps你可以理解成在下面connect的時(shí)候?yàn)榻M件提供一個(gè)props,這個(gè)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
創(chuàng)建View
在View里面我們會(huì)接受到兩個(gè)props。一個(gè)是在mapStateToProps生成的state,一個(gè)是store給我們的dispatch,這是是一個(gè)函數(shù),我們用它的方法很簡(jiǎn)單粗暴,往里面?zhèn)魅胍粋€(gè)Action就行了,它接受了這個(gè)Action就會(huì)告訴reducer去執(zhí)行。
文件位置: app/compoment/index.js
'use strict'
import React from 'react'
import { connect } from 'react-redux'
//請(qǐng)注意這里面引入了action
import {increaseAction} from '../redux/action'
let {Component,PropTypes} = React
class Index extends Component{
//這一步是檢查傳入的各個(gè)prop類型是否正確
ProTypes = {
count:PropTypes.number.isRequired,
}
constructor(props){
super(props)
}
handleClick(){
/*
這一步輸入this.props可以看到,其實(shí)里面有兩個(gè)東西
在下面的render里面我們用到了this.props.count這個(gè)
那么這里我們要用到dispatch
*/
console.log(this.props)
let {dispatch} = this.props
//粗暴簡(jiǎn)單的使用
dispatch(increaseAction)
}
render(){
let {count} = this.props
return <div onClick = {this.handleClick.bind(this)} style={styles.circle}>{count}</div>
}
}
//樣式文件,不用細(xì)看
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
進(jìn)一步優(yōu)化代碼
要做一個(gè)點(diǎn)擊遞增就需要那么多步驟是不是很煩惱?但是如果項(xiàng)目大起來之后,你想像這樣,你就可以創(chuàng)建不同的鑰匙Action,再編寫不同的生產(chǎn)線reducer來修改各自的state,但是如上所做,我們的邏輯代碼(點(diǎn)擊遞增)和View還是捆綁在一起(就是在組件里面使用dispatch)這個(gè)方法是不可取的。所以下一步我們就要進(jìn)一步優(yōu)化我們的代碼
文件位置: 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'
/*
注意:這里是新增的
相對(duì)原來,我們?cè)谧钔鈱哟虬@里引入Action
*/
import {increaseAction} from '../redux/action'
//創(chuàng)建store
let store = createStore(reducers)
/*
mapStateToProps你可以理解成在下面connect的時(shí)候提供一個(gè)state
*/
let mapStateToProps = (state) =>{
return {count:state.count}
}
/*
注意:這里是新增的
mapDispatchToProps你可以理解成在下面connect的時(shí)候提供一個(gè)放置好鑰匙的函數(shù)onIncreaseClick,直接調(diào)用就可以去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'
/*
注意:這里是修改樂的
現(xiàn)在不用引入action了,因?yàn)榍耙徊揭呀?jīng)把鑰匙Action放到相應(yīng)的函數(shù)中去,作為props傳入組件里面
*/
//import {increaseAction} from '../redux/action'
let {Component,PropTypes} = React
class Index extends Component{
//這一步是檢查傳入的各個(gè)prop類型是否正確
ProTypes = {
count:PropTypes.number.isRequired,
onIncreaseClick:PropTypes.func.isRequired,
}
constructor(props){
super(props)
}
handleClick(){
/*
注意:這里是修改過的
現(xiàn)在,我們把打包好的,帶著鑰匙的函數(shù)進(jìn)行調(diào)用
*/
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>
}
}
//樣式文件,不用細(xì)看
...(以下相同就略去)
結(jié)語(yǔ)
redux其實(shí)不難理解,按照我個(gè)人理解的加工工廠模式:有一家大公司叫做store,里面有工廠(reducer),公司(store)只有一家,但這家公司(store)可以有很多工廠(reducer)。要進(jìn)去工廠加工產(chǎn)品(state),就得帶上相應(yīng)得鑰匙(Action),不同的鑰匙(Action)對(duì)應(yīng)工廠中上不同的生產(chǎn)線(redecer里面的switch函數(shù)),從而有不同的產(chǎn)出(改變之后的state)//這個(gè)在下一步創(chuàng)建