《React-Native系列》24、 结合Demo学习Redux框架

8月的最后一天了,那就打响最后一炮吧!

我们介绍了Flux框架,我们打算在接下来的项目里使用Redux框架,这两天简单学习了下Redux。打算结合一个Demo来讲解。

还是先来说说概念吧。

Redux 三个基本原则

  • 单一数据源
整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。


这让同构应用开发变得非常容易。来自服务端的 state 可以在无需编写更多代码的情况下被序列化并注入到客户端中。由于是单一的 state tree ,调试也变得非常容易。在开发中,你可以把应用的 state 保存在本地,从而加快开发速度。此外,受益于单一的 state tree ,以前难以实现的如“撤销/重做”这类功能也变得轻而易举。

  • State 是只读的
惟一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。
这样确保了视图和网络请求都不能直接修改 state,相反它们只能表达想要修改的意图。因为所有的修改都被集中化处理,且严格按照一个接一个的顺序执行,因此不用担心 race condition 的出现。 Action 就是普通对象而已,因此它们可以被日志打印、序列化、储存、后期调试或测试时回放出来。

  • 使用纯函数来执行修改
为了描述 action 如何改变 state tree ,你需要编写 reducers。


我们再来介绍下Redux中有三个基本概念,Action,Reducer,Store。

Action

Action 本质上是 JavaScript 普通对象。我们约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作。多数情况下,type 会被定义成字符串常量。当应用规模越来越大时,建议使用单独的模块或文件来存放 action。

代码如下:

export const addTodo = (num) => {
  return {
    type: 'INCREMENT',
    num: num,
  }
}

export const decTodo = (num) => {
  return {
    type: 'DECREMENT',
    num: num,
  }
}

export const updateText = (text) => {
  return {
    type: 'TEXT_UPDATE',
    text: text,
  }
}

Reducer

reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。

(previousState, action) => newState
保持 reducer 纯净非常重要。永远不要在 reducer 里做这些操作:
1、修改传入参数;
2、执行有副作用的操作,如 API 请求和路由跳转;
3、调用非纯函数,如 Date.now() 或 Math.random()。

我们定义了2个reduce (reduceNum.js   reduceText.js)

reduceNum如下:

const todo = (state=0, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state//返回原来的state
  }
}

export default todo

reduceText如下:

const todo = (state="", action) => {

  switch (action.type) {
    case 'TEXT_UPDATE':
    //新的state
      return  action.text 
    default:
      //返回原来的state
      return state
  }
}

export default todo


我们使用combineReducers 合并reduce

import { combineReducers } from 'redux'
import reduceNum from './reduceNum'
import reduceText from './reduceText'

const todoApp = combineReducers({
  num:reduceNum,
  text:reduceText
})

export default todoApp

关于 combineReducers 参考http://cn.redux.js.org/docs/api/combineReducers.html

Store

Store 就是把action和reduce联系到一起的对象。Store 有以下职责:

  • 维持应用的 state;
  • 提供 getState() 方法获取 state;
  • 提供 dispatch(action) 方法更新 state;
  • 通过 subscribe(listener) 注册监听器;
  • 通过 subscribe(listener) 返回的函数注销监听器。
再次强调一下 Redux 应用只有一个单一的 store。当需要拆分数据处理逻辑时,你应该使用 reducer 组合 而不是创建多个 store。

根据已有的 reducer 来创建 store 是非常容易的。我们使用 combineReducers() 将多个 reducer 合并成为一个。现在我们将其导入,并传递 createStore()。
import reducers from './reducers'
import { createStore } from 'redux'

let initState = { num: 0,text:""};
let store = createStore(reducers,initState);
createStore() 的第二个参数是可选的, 用于设置 state 初始状态。


好了,概念就介绍到这儿,贴下Demo的源码。

入口组件:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

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


import { createStore } from 'redux'
import { Provider } from 'react-redux'

import reducers from './reducers'

import AddTodo from './containers/AddTodo'

class reduxdemo extends Component {

  render() {
    // let initState = { num: 0,text:""};
    let store = createStore(reducers);
    return (
        <Provider store={store}>
          <AddTodo />
        </Provider>
    )
  }
}


AppRegistry.registerComponent('reduxdemo', () => reduxdemo);

视图组件:AddTodo

import React,{Component} from 'react'
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableHighlight,
  Dimensions,
} from 'react-native';
import { connect,Provider } from 'react-redux'
import { addTodo,decTodo,updateText } from '../actions'

const {width, height} = Dimensions.get('window');

class AddTodo extends Component {
    constructor(props) {
      super(props);
    }

    render() {
      const { dispatch,num ,text} = this.props
      // alert(num);
      return (
        <View style={styles.container}>
          <TouchableHighlight style={styles.itemView} underlayColor="red" onPress={()=>{dispatch(addTodo(num))}}>
              <Text style={styles.itemText}>
                点击我就+1
              </Text>
          </TouchableHighlight>

          <TouchableHighlight style={styles.itemView} underlayColor="red" onPress={()=>{dispatch(decTodo(num))}}>
              <Text style={styles.itemText}>
                点击我就-1
              </Text>
          </TouchableHighlight>

          <TouchableHighlight style={styles.itemView} underlayColor="red" onPress={()=>{dispatch(updateText('测试'))}}>
              <Text style={styles.itemText}>
                修改Text的值
              </Text>
          </TouchableHighlight>

          <Text style={{paddingTop:10,color:'red'}}>
            当前的Num值是:{num} , 当前的Text值是:{text}
          </Text>
        </View>
      )
    }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f2f2f2',
    marginTop:20,
  },
  itemView:{
    backgroundColor:'grey',
    height:44,
    width:width,
    justifyContent:'center',
    marginTop:10,
  },
  itemText:{
    fontSize:15,
    color:'#ffffff',
    textAlign:'left',
    marginLeft:20,
  },
});

//selector:这是你自己编写的一个函数。这个函数声明了你的组件需要整个 store 中的哪一部分数据作为自己的 props。
function selector(state) {
  return {
    num: state.num ,
    text:state.text
  }
}

// 包装 component ,注入 dispatch 和 state 到其默认的 connect(selector)(App) 中;
export default connect(selector)(AddTodo);

Demo运行的效果如下:



代码结构目录如下:



写在后面的话:

Redux真不是一两句话可以说清楚的,这里提供了一个简单的完整Demo,希望可以帮助到大家。


参考:http://cn.redux.js.org/index.html


           



  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值