redux中connect的使用(3)-最简单的一个傻瓜app

在(1)中我讲了一个电灯的例子,用开关来控制等的状态的变化,
现在把它用react-native/redux来实现了,比counter还要简单,只有一个状态的改变,都已经写好了,还可以作为一个框架来使用。安装了redux-logger以后,可以在按下按钮的时候实时的看到状态的变化。同时结合在UI组件中的console.log的方法,基本解决了redux调试的方法问题。在Component中导入了react-native-elements组件库。这个和bootstrap的效果类似,封装了很多的组件可以直接来使用,这个组件库可以换为native-base组件库。在组件中修改UI 完全不改变app的交互操作的逻辑。就这个简单的app就做了一下午,主要原因是一个也是初学,另外一个问题为了调试加进去了好多的console.log(),完全搞乱的出现问题的原因,但是这个坑还是值得的。主要的目的就是给需要学习redux的同学提供一个简单的教程。redux的学习也要不断的反复拿捏才行,理解以后其实觉得redux的思想其实很简单,但是要发生这个转变需要一定的时间,当然有基础的高手除外。

github代码在这

界面就是这么一个,有一个灯,下面有一个开关,要解决的问题就是按下按钮的操作使灯的状态发生变化,Component里面有两个文件,一个是直接在组件中操作,另外一个就是我们这里的主题,组件中操作以后,state在redux中绕了一圈以后回到组件中,组件的状态就发生了变化,这里组件和redux是分开的,在学习的时候等你体会到这种分开的情况就离理解差不多了。

要时刻注意的是流程,组件和redux的衔接
1. 组件的操作是怎么在Redux中对上暗号,接上头的
2.Redux中状态发生改变之后又是怎么返回的组件的
以上两点就是connect的内容,关键就在这里。

screenshot_16.png
screenshot_17.png

下面是文件的结构,稍等我放到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 = { //初始化状态
      light: false
    }
  }
  componentDidMount() {}
  shut() {  //组件中直接操作的函数,负责改变状态
     this.setState({
       light : !this.state.light //状态发生翻转
     })
  }
  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='开关' />

          </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组件库
//你可以选择其他的组件库,加速开发流程。


class Lamp extends Component {

  constructor(props) {
    super(props);
   
  componentDidMount() {}
  render() {
     //下面这一句是理解的难点,在react中组件都是在使用的时
//候,通过注入props来获取一些参数,下面这两个参数,一个是操
//作的方法名,一个是灯的状态,初学的时候很难理解这两个东西 
//到底是从哪里来的。其实有点远,组件获取这两个东西的地方是
//在container文件夹中,container文件其实做的内容很少,就是
//要建立组件和Redux之间的联系,这两个东西也就是在那里注入进来的
     const { switchLamp,light} = this.props;    
      console.log(light.light); //这个语句可以随时监测light的状态是
     //false还是true.
    //下面这个三元判断就是根据light的状态来决定加载哪一张图片
      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是函数,然而这个函数并不在这里执
//行,我在container里面吧这个函数绑定到了dispatch上
//这样,执行这个函数,绑定地就会执行一个dispatch(),dispatch的意思
//是分发,那么分发这个函数到什么地方呢?这个函数和action
//中一个函数名字是一样的,这样发生在组件中的函数动作就会和
//redux中的函数名配对了,redux就感知到了组件要干什么,所谓
//对上眼了,对上暗号了。这里我们约定好函数名只由redux中的
//action来定义,组件中直接来用,这样就不会发生错误匹配的问题 
//这里的onPress函数式唯一和操作逻辑相关的地方,如果修改组
//件样式,或者更换组件,只保留这个函数就可以了,其他的都可
//样式和逻辑彻底分开了,当然这是理想化的,实际操作的是后,
//也是挺复杂的。
                     onPress={() => switchLamp()} />
          </View>
        );

    }

}

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

export default Lamp;

既然上面的函数已经和Redux已经对上眼了,我们就马上看看,
他们是怎么对上的

//lamp/src/containers/App.js
  import { bindActionCreators } from 'redux'; //用来绑定函数和dispatch()
import { connect } from 'react-redux'; //redux和component的中间代理人
import  Lamp from '../components/Lamp'; //这就是上面讲的组件
import  * as switchLamp from '../actions/lamp'; //获取actions中
//定义的action函数,这里并不是要这些函数做什么,而是给组件一套对暗号的密码表,
//mapStateToProps,看名字就是State转变为Props,state是在
//redux中的,组件在使用的时候是通过props来获取参数的,
//所以这里有这么一个转变的过程

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

  light:state.light //这里的state比较简单,可以很复杂
  };
}
 //这里把方法也转为props,以供组件使用
function mapDispatchToProps(dispatch) {
   //使用bindActionCreators来绑定dispatch和函数
  //这是switchLamp看起来是一个函数,其实是一个对象,
  //包含了actions里定义的所有函数
 //组件中的函数就会自动dispatch到actions中和对应的函数想匹配,dispatch以后redux就接管了后续的逻辑操作
    return bindActionCreators(switchLamp, dispatch);

}

//connect是我们这个系列要讲的核心,所有的内容其实都是围绕
//他,尽管这一句,但是是非常重要的,经过这么connect以后
//组件就获取了所需的方法名和props,
//connect其实是很灵活的,没有规定只能connect一次,
//所有的组件都可以用他来包装,看其他代买的时候要注意
//因为一旦程序规模变大,action里面的函数就不好一次注入了,
//在不同的组件中注入自己需要的函数和props是很好的选择。
export default connect(mapStateToProps, mapDispatchToProps)(Lamp);

组件dispatch 一个函数以后,redux就接管了后续的操作。 进入到actions中

//actions/lamp.js
 export const SWITCH = 'SWITCH'; //这个常量是给reducer用的
//在redux中有几个地方可以打印state看看,但是这个文件中
//绝对不能打印state
import React, { Component } from 'react';
import {SWITCH} from '../constants/ActionTypes';//也可以在这里定义常量
//下面的这个函数和组件dispatch的函数名是一样的时候,就会执
//行操作,这个操作拿着type的类型去操作state的改变。
//你看凡是逻辑分离的地方都要对这个信号
export function switchLamp() {
  return {
    type: SWITCH,
  };
};
 

上面的type 就会和redcer匹配,reducer的作用是改变state,
state对象其实就相当于一个数据库,用来存储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, // 返回一个新的状态,取反就可以了
                                       //ui 组件中就可以根据这个变化来改变状态
        };
      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其实不实际干活,而是
一个发号施令的角色。所有的操作和所有的状态变化他都知道,
所以我们可以在这里监控整个程序的变化,redux-logger在store里面注入就可以监视变化了

  //看起来比较复杂
 //这里面还注入了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中改变的状态有要返回组件中
我把container的代码再粘贴一遍,但是注意这一次的container
和刚开始的container实际是不同的,state发生了改变了。

  //lamp/src/containers/App.js
  import { bindActionCreators } from 'redux'; //用来绑定函数和dispatch()
import { connect } from 'react-redux'; //redux和component的中间代理人
import  Lamp from '../components/Lamp'; //这就是上面讲的组件
import  * as switchLamp from '../actions/lamp'; //获取actions中
//定义的action函数,这里并不是要这些函数做什么,而是给组件一套对暗号的密码表,
//mapStateToProps,看名字就是State转变为Props,state是在
//redux中的,组件在使用的时候是通过props来获取参数的,
//所以这里有这么一个转变的过程

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

  light:state.light //这里的state比较简单,可以很复杂
  };
}
 //这里把方法也转为props,以供组件使用
function mapDispatchToProps(dispatch) {
   //使用bindActionCreators来绑定dispatch和函数
  //这是switchLamp看起来是一个函数,其实是一个对象,
  //包含了actions里定义的所有函数
 //组件中的函数就会自动dispatch到actions中和对应的函数想匹配,dispatch以后redux就接管了后续的逻辑操作
    return bindActionCreators(switchLamp, dispatch);

}

//connect是我们这个系列要讲的核心,所有的内容其实都是围绕
//他,尽管这一句,但是是非常重要的,经过这么connect以后
//组件就获取了所需的方法名和props,
//connect其实是很灵活的,没有规定只能connect一次,
//所有的组件都可以用他来包装,看其他代买的时候要注意
//因为一旦程序规模变大,action里面的函数就不好一次注入了,
//在不同的组件中注入自己需要的函数和props是很好的选择。
export default connect(mapStateToProps, mapDispatchToProps)(Lamp);

至此组件中的操作数据流程就完成了。

这个是比较简单的,但是redux的基本流程和框架就是这样的。
我在(1)中讲了,因为组件和redux是解耦和,改变任意一个,另一个不发生变化就可以很好的工作。下面我们能不能再进一步?
灯的开关也可以换成声控的,有声音以后会延迟一段时间再灭,
如果继续有声音,灯还会亮着。能实现吗?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容