redux中connect的使用(3)-最簡單的一個傻瓜app

在(1)中我講了一個電燈的例子,用開關(guān)來控制等的狀態(tài)的變化原环,
現(xiàn)在把它用react-native/redux來實現(xiàn)了箕肃,比counter還要簡單,只有一個狀態(tài)的改變粹懒,都已經(jīng)寫好了重付,還可以作為一個框架來使用。安裝了redux-logger以后凫乖,可以在按下按鈕的時候?qū)崟r的看到狀態(tài)的變化确垫。同時結(jié)合在UI組件中的console.log的方法,基本解決了redux調(diào)試的方法問題帽芽。在Component中導入了react-native-elements組件庫删掀。這個和bootstrap的效果類似,封裝了很多的組件可以直接來使用导街,這個組件庫可以換為native-base組件庫披泪。在組件中修改UI 完全不改變app的交互操作的邏輯。就這個簡單的app就做了一下午搬瑰,主要原因是一個也是初學款票,另外一個問題為了調(diào)試加進去了好多的console.log(),完全搞亂的出現(xiàn)問題的原因,但是這個坑還是值得的泽论。主要的目的就是給需要學習redux的同學提供一個簡單的教程徽职。redux的學習也要不斷的反復拿捏才行,理解以后其實覺得redux的思想其實很簡單佩厚,但是要發(fā)生這個轉(zhuǎn)變需要一定的時間姆钉,當然有基礎(chǔ)的高手除外。

github代碼在這

界面就是這么一個抄瓦,有一個燈潮瓶,下面有一個開關(guān),要解決的問題就是按下按鈕的操作使燈的狀態(tài)發(fā)生變化钙姊,Component里面有兩個文件毯辅,一個是直接在組件中操作,另外一個就是我們這里的主題煞额,組件中操作以后思恐,state在redux中繞了一圈以后回到組件中沾谜,組件的狀態(tài)就發(fā)生了變化,這里組件和redux是分開的胀莹,在學習的時候等你體會到這種分開的情況就離理解差不多了基跑。

要時刻注意的是流程,組件和redux的銜接
1. 組件的操作是怎么在Redux中對上暗號描焰,接上頭的
2.Redux中狀態(tài)發(fā)生改變之后又是怎么返回的組件的
以上兩點就是connect的內(nèi)容媳否,關(guān)鍵就在這里。

screenshot_16.png
screenshot_17.png

下面是文件的結(jié)構(gòu)荆秦,稍等我放到github上去篱竭。


screenshot_15.png

下面先從視覺組件開始

先貼一下直接在組件中操作的邏輯例子

'use strict';
import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Image,
  ListView,
} from 'react-native';

import * as lampAction from '../actions/lamp';
//import {Container, Header, Title, Content,Button } from 'native-base';
import {
  Button
} from 'react-native-elements'

class Lamp extends Component {
  constructor(props) {
    super(props);
    this.state = { //初始化狀態(tài)
      light: false
    }
  }
  componentDidMount() {}
  shut() {  //組件中直接操作的函數(shù),負責改變狀態(tài)
     this.setState({
       light : !this.state.light //狀態(tài)發(fā)生翻轉(zhuǎn)
     })
  }
  render() {
    this.shut=this.shut.bind(this);
       //console.log(light); //可以在組件中打印state
         //light==false?(uri=' ./image/off.png'):(uri=' ./image/on.png');
      var status = this.state.light==false
      ? require('./image/off.png')
      : require('./image/on.png');
        return (
          <View style={styles.container}>
          <Image source={status}
                style={styles.customimg}
          />
          <Button
              style={styles.buttonMargin}
              raised
              onPress={ this.shut}
              title='開關(guān)' />

          </View>

        );


    }

}
var styles=StyleSheet.create({
    //樣式省略
});
export default Lamp;

下面是作為導入redux以后的組件代碼

//Lamp/src/component/Lamp.js
  'use strict';
import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Image,
  ListView
} from 'react-native';
import {
  Button,
  Icon,
  SocialIcon
} from 'react-native-elements'; //導入的elements組件庫
//你可以選擇其他的組件庫步绸,加速開發(fā)流程掺逼。


class Lamp extends Component {

  constructor(props) {
    super(props);
   
  componentDidMount() {}
  render() {
     //下面這一句是理解的難點,在react中組件都是在使用的時
//候瓤介,通過注入props來獲取一些參數(shù)坪圾,下面這兩個參數(shù),一個是操
//作的方法名,一個是燈的狀態(tài)惑朦,初學的時候很難理解這兩個東西 
//到底是從哪里來的。其實有點遠漓概,組件獲取這兩個東西的地方是
//在container文件夾中漾月,container文件其實做的內(nèi)容很少,就是
//要建立組件和Redux之間的聯(lián)系胃珍,這兩個東西也就是在那里注入進來的
     const { switchLamp,light} = this.props;    
      console.log(light.light); //這個語句可以隨時監(jiān)測light的狀態(tài)是
     //false還是true.
    //下面這個三元判斷就是根據(jù)light的狀態(tài)來決定加載哪一張圖片
      var status =light.light==false
      ? require('./image/off.png')
      : require('./image/on.png');
        return (
          <View style={styles.container}>
              <Image source={status}
                     style={styles.customimg}/>
              <Icon
                     raised
                     name='heartbeat'
                     type='font-awesome'
                     color='#f50'
  //這個地方的switchLamp是函數(shù)梁肿,然而這個函數(shù)并不在這里執(zhí)
//行,我在container里面吧這個函數(shù)綁定到了dispatch上
//這樣觅彰,執(zhí)行這個函數(shù)吩蔑,綁定地就會執(zhí)行一個dispatch(),dispatch的意思
//是分發(fā),那么分發(fā)這個函數(shù)到什么地方呢填抬?這個函數(shù)和action
//中一個函數(shù)名字是一樣的烛芬,這樣發(fā)生在組件中的函數(shù)動作就會和
//redux中的函數(shù)名配對了,redux就感知到了組件要干什么飒责,所謂
//對上眼了赘娄,對上暗號了。這里我們約定好函數(shù)名只由redux中的
//action來定義宏蛉,組件中直接來用遣臼,這樣就不會發(fā)生錯誤匹配的問題 
//這里的onPress函數(shù)式唯一和操作邏輯相關(guān)的地方,如果修改組
//件樣式拾并,或者更換組件揍堰,只保留這個函數(shù)就可以了鹏浅,其他的都可
//樣式和邏輯徹底分開了,當然這是理想化的屏歹,實際操作的是后隐砸,
//也是挺復雜的。
                     onPress={() => switchLamp()} />
          </View>
        );

    }

}

var styles=StyleSheet.create({
    //樣式代碼省略
});

export default Lamp;

既然上面的函數(shù)已經(jīng)和Redux已經(jīng)對上眼了西采,我們就馬上看看凰萨,
他們是怎么對上的

//lamp/src/containers/App.js
  import { bindActionCreators } from 'redux'; //用來綁定函數(shù)和dispatch()
import { connect } from 'react-redux'; //redux和component的中間代理人
import  Lamp from '../components/Lamp'; //這就是上面講的組件
import  * as switchLamp from '../actions/lamp'; //獲取actions中
//定義的action函數(shù),這里并不是要這些函數(shù)做什么,而是給組件一套對暗號的密碼表械馆,
//mapStateToProps,看名字就是State轉(zhuǎn)變?yōu)镻rops胖眷,state是在
//redux中的,組件在使用的時候是通過props來獲取參數(shù)的,
//所以這里有這么一個轉(zhuǎn)變的過程

function mapStateToProps(state, props) {
  //console.log(state);
  return {

  light:state.light //這里的state比較簡單霹崎,可以很復雜
  };
}
 //這里把方法也轉(zhuǎn)為props珊搀,以供組件使用
function mapDispatchToProps(dispatch) {
   //使用bindActionCreators來綁定dispatch和函數(shù)
  //這是switchLamp看起來是一個函數(shù),其實是一個對象尾菇,
  //包含了actions里定義的所有函數(shù)
 //組件中的函數(shù)就會自動dispatch到actions中和對應的函數(shù)想匹配境析,dispatch以后redux就接管了后續(xù)的邏輯操作
    return bindActionCreators(switchLamp, dispatch);

}

//connect是我們這個系列要講的核心,所有的內(nèi)容其實都是圍繞
//他派诬,盡管這一句劳淆,但是是非常重要的,經(jīng)過這么connect以后
//組件就獲取了所需的方法名和props,
//connect其實是很靈活的默赂,沒有規(guī)定只能connect一次沛鸵,
//所有的組件都可以用他來包裝,看其他代買的時候要注意
//因為一旦程序規(guī)模變大缆八,action里面的函數(shù)就不好一次注入了曲掰,
//在不同的組件中注入自己需要的函數(shù)和props是很好的選擇。
export default connect(mapStateToProps, mapDispatchToProps)(Lamp);

組件dispatch 一個函數(shù)以后奈辰,redux就接管了后續(xù)的操作栏妖。 進入到actions中

//actions/lamp.js
 export const SWITCH = 'SWITCH'; //這個常量是給reducer用的
//在redux中有幾個地方可以打印state看看,但是這個文件中
//絕對不能打印state
import React, { Component } from 'react';
import {SWITCH} from '../constants/ActionTypes';//也可以在這里定義常量
//下面的這個函數(shù)和組件dispatch的函數(shù)名是一樣的時候奖恰,就會執(zhí)
//行操作吊趾,這個操作拿著type的類型去操作state的改變。
//你看凡是邏輯分離的地方都要對這個信號
export function switchLamp() {
  return {
    type: SWITCH,
  };
};
 

上面的type 就會和redcer匹配瑟啃,reducer的作用是改變state趾徽,
state對象其實就相當于一個數(shù)據(jù)庫,用來存儲app的所有變化翰守。
在redux中把state定義為一個??孵奶,樹有各個部分,果實可以吃蜡峰,
葉子可以做藥材了袁,樹皮可以做電纜朗恳,樹干可以蓋房子,樹根可以做根雕载绿。 當你要吃果實的時候只需要去摘果實就可以了粥诫,并不需要把整個樹都弄到,所以需要進行過濾崭庸。 這個過程是在container中來完成的怀浆。我們的這個實例比較簡單,只是一顆種子怕享,么辦法過濾执赡。
下面就看看reducer做了什么工作

//lamp/reducers/lamp.js
//先導入actiontype,這樣從aciton過來的動作函筋,reducer就知道要干什么
   import { SWITCH } from '../constants/ActionTypes';
//初始化一顆樹沙合,先種下一顆種子,隨著程序的變大跌帐,這棵樹也變大
const initialState = {
    light: false
};
//實際的操作就在這里了首懈,
export default function light(state=initialState, action) {
  switch (action.type) {  //進行匹配
    case SWITCH: //匹配上了
     
      return {
          light:!state.light, // 返回一個新的狀態(tài),取反就可以了
                                       //ui 組件中就可以根據(jù)這個變化來改變狀態(tài)
        };
      default:
      return state;
  };
}

//有時候程序較復雜,reducer寫在一起很難理解谨敛,所以就會分開
//最終會合并成一個
//lamp/reducers/index.js
import { combineReducers } from 'redux';
//import film from './film';
import light from './lamp';
const rootReducer = combineReducers({
   light
});
export default rootReducer;

組件所需要的邏輯操作就在reducers中完成了究履。

reducer改變的邏輯交給store,這個store其實不實際干活脸狸,而是
一個發(fā)號施令的角色最仑。所有的操作和所有的狀態(tài)變化他都知道,
所以我們可以在這里監(jiān)控整個程序的變化肥惭,redux-logger在store里面注入就可以監(jiān)視變化了

  //看起來比較復雜
 //這里面還注入了redux-sage這個是用來進行異步操作的邏輯
//在這里涉及不到。

   import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware, { END } from 'redux-saga';

import rootReducer from '../reducers/index'; 注入reducer到store

const middlewares = [];
const createLogger = require('redux-logger');

// configuring saga middleware
const sagaMiddleware = createSagaMiddleware();

middlewares.push(sagaMiddleware);

if (process.env.NODE_ENV === 'development') {
  const logger = createLogger();
  middlewares.push(logger);
}
const createStoreWithMiddleware = applyMiddleware(...middlewares)(createStore);

export default function configureStore(initialState) {
  const store = createStoreWithMiddleware(rootReducer, initialState);
  // install saga run
  store.runSaga = sagaMiddleware.run;
  store.close = () => store.dispatch(END);

  return store;
}

下面我們在返回container,reducer中改變的狀態(tài)有要返回組件中
我把container的代碼再粘貼一遍紊搪,但是注意這一次的container
和剛開始的container實際是不同的蜜葱,state發(fā)生了改變了。

  //lamp/src/containers/App.js
  import { bindActionCreators } from 'redux'; //用來綁定函數(shù)和dispatch()
import { connect } from 'react-redux'; //redux和component的中間代理人
import  Lamp from '../components/Lamp'; //這就是上面講的組件
import  * as switchLamp from '../actions/lamp'; //獲取actions中
//定義的action函數(shù),這里并不是要這些函數(shù)做什么耀石,而是給組件一套對暗號的密碼表牵囤,
//mapStateToProps,看名字就是State轉(zhuǎn)變?yōu)镻rops,state是在
//redux中的,組件在使用的時候是通過props來獲取參數(shù)的滞伟,
//所以這里有這么一個轉(zhuǎn)變的過程

function mapStateToProps(state, props) {
  //console.log(state);
  return {

  light:state.light //這里的state比較簡單揭鳞,可以很復雜
  };
}
 //這里把方法也轉(zhuǎn)為props,以供組件使用
function mapDispatchToProps(dispatch) {
   //使用bindActionCreators來綁定dispatch和函數(shù)
  //這是switchLamp看起來是一個函數(shù)梆奈,其實是一個對象野崇,
  //包含了actions里定義的所有函數(shù)
 //組件中的函數(shù)就會自動dispatch到actions中和對應的函數(shù)想匹配,dispatch以后redux就接管了后續(xù)的邏輯操作
    return bindActionCreators(switchLamp, dispatch);

}

//connect是我們這個系列要講的核心亩钟,所有的內(nèi)容其實都是圍繞
//他乓梨,盡管這一句鳖轰,但是是非常重要的,經(jīng)過這么connect以后
//組件就獲取了所需的方法名和props,
//connect其實是很靈活的扶镀,沒有規(guī)定只能connect一次蕴侣,
//所有的組件都可以用他來包裝,看其他代買的時候要注意
//因為一旦程序規(guī)模變大臭觉,action里面的函數(shù)就不好一次注入了昆雀,
//在不同的組件中注入自己需要的函數(shù)和props是很好的選擇。
export default connect(mapStateToProps, mapDispatchToProps)(Lamp);

至此組件中的操作數(shù)據(jù)流程就完成了蝠筑。

這個是比較簡單的狞膘,但是redux的基本流程和框架就是這樣的。
我在(1)中講了菱肖,因為組件和redux是解耦和客冈,改變?nèi)我庖粋€,另一個不發(fā)生變化就可以很好的工作稳强。下面我們能不能再進一步场仲?
燈的開關(guān)也可以換成聲控的,有聲音以后會延遲一段時間再滅退疫,
如果繼續(xù)有聲音渠缕,燈還會亮著。能實現(xiàn)嗎褒繁?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末亦鳞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子棒坏,更是在濱河造成了極大的恐慌燕差,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坝冕,死亡現(xiàn)場離奇詭異徒探,居然都是意外死亡,警方通過查閱死者的電腦和手機喂窟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門测暗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人磨澡,你說我怎么就攤上這事碗啄。” “怎么了稳摄?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵稚字,是天一觀的道長。 經(jīng)常有香客問我厦酬,道長尉共,這世上最難降的妖魔是什么褒傅? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮袄友,結(jié)果婚禮上殿托,老公的妹妹穿的比我還像新娘。我一直安慰自己剧蚣,他們只是感情好支竹,可當我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鸠按,像睡著了一般礼搁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上目尖,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天馒吴,我揣著相機與錄音,去河邊找鬼瑟曲。 笑死饮戳,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的洞拨。 我是一名探鬼主播扯罐,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼烦衣!你這毒婦竟也來了歹河?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤花吟,失蹤者是張志新(化名)和其女友劉穎秸歧,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衅澈,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡键菱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了矾麻。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纱耻。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡芭梯,死狀恐怖险耀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情玖喘,我是刑警寧澤甩牺,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站累奈,受9級特大地震影響贬派,放射性物質(zhì)發(fā)生泄漏急但。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一搞乏、第九天 我趴在偏房一處隱蔽的房頂上張望波桩。 院中可真熱鬧,春花似錦请敦、人聲如沸镐躲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萤皂。三九已至,卻和暖如春匣椰,著一層夾襖步出監(jiān)牢的瞬間裆熙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工禽笑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留入录,地道東北人。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓蒲每,卻偏偏與公主長得像纷跛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子邀杏,可洞房花燭夜當晚...
    茶點故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容