Back

reactnative - 15. Redux 重量级组件状态存储组件

发布时间: 2018-12-26 06:58:00

参考:https://redux.js.org/introduction/getting-started

redux 是 react团队开发的:  可预测的保存状态的容器。(predictable state container for js app)

这句话非常拗口。 

举个例子: 

我们在登录页面点击 发送 短信验证码,按照1分钟倒计时的话,无论我们跳转到哪个其他的页面,再跳转回来,都应该可以看到这个页面的倒计时在不断的下降。 这个倒计时是不收页面的各种刷新的影响的。 

这个就是一种“状态” (state)

也可以简单的认为, redux就是vuejs中的vuex , 是一种很高级的存储类库。

安装:

$ npm install --save redux

store:  保存data ,  

reducer: 是store的参数。 是一个function .用来“变换” store中的数据

actionCreator:  该方法返回的值, 就是store.dispatch()的参数

redux 对于异步的操作,是需要通过中间件来完成的,使用的时候,跟同步的效果是一样的。

store发生变化之后,可以使用subscribe来通知:

// 就是通过这个方法来感知某个store发生了变化
// 这里的subcribe 应该重命名成: notify
store_0.subscribe(function(){
console.log('== store_0 has been updated, new state: ', store_0.getState())
})

React Native 中的用法:读取数据,并更新页面状态(计数器,点一下两秒后改变,并刷新页面)

React Native 中使用 redux

参考:https://appdividend.com/2018/08/04/react-native-redux-example-tutorial/?bs-comment-added=1#comment-20105 (单页面中使用 ) 和

  https://moduscreate.com/blog/react-navigation-redux-in-react-native-applications/  (StackNavigator中使用)

1. 安装第三方包

npm install redux react-redux --save

2. 增加首页入口,路由。 

修改 Home.js,   App.js  ,过程略。 

3. 增加骨架文件:screens/ReduxDemo.js

import React,  { Component} from 'react';
import {Image, Platform, StyleSheet, Text, View, Button} from 'react-native'


export default class ReduxDemo extends Component{
  constructor(props){
    super(props)
  }

  render(){
    return(
      <View>
        <Text>本例子演示Redux在React Native中的使用: 保存数据和状态。 {"\n"}
        1. 点击之后,计数器 + 1 {"\n"}
        2. 点击之后,5秒内 按钮不可点击 。
        </Text>
        <Button
          title="点击计数!"
          onPress={ () => {
              // do nothing
          }}
          />
      </View>
    )
  }
}

  然后,分别建立:  reducer,   =>  store  => connect 

建立reducer: 

新建文件夹: redux_demo, 然后在其中:

1. 新建 types.js

export const INCREASE_COUNT = 'INCREASE_COUNT'

2. 新建 action creator.js: 

import { INCREASE_COUNT } from './types'

export const increaseCount = (para) => {

  // type 参数是必须有的,  其他的可以自行填写。这里就是一个 填参数的过程。
  return {
    type: INCREASE_COUNT
  }
}

3. 新建 reducers.js

import { INCREASE_COUNT} from './types'

const initialState = {
  count: 0
  // isClickable: true
}

const countReducer = (state = initialState, action ) => {
  switch(action.type) {
    case INCREASE_COUNT:
      console.info("== count: ", state.count)
      return {
        // ...state,
        count: state.count + 1  // 我们只关心这一个就好了。
      }
    default:
      return state
  }
}

export default countReducer

4. 建立store.js 

import {createStore, combineReducers} from 'redux'
import countReducer from './reducers'

const rootReducer = combineReducers({
  countReducer: countReducer
})

const configureStore = () => {
  return createStore(rootReducer)
}

export default configureStore

5. 修改 入口文件  index.js

/** @format */

import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';

// 以下为 为调用Redux 而新增的代码
// 这句话虽然没有被显示调用,但是不加会报错, 在 const myProvider那里。
import React from 'react'
import configureStore from './redux_demo/store'
import { Provider } from 'react-redux'
const store = configureStore()
const myProvider = () => {

  // 这里要记得使用 return , 否则会报错:
  // 网上这个例子是错的:
  // 参考:https://stackoverflow.com/questions/49075731/invariant-violation-app-nothing-was-returned-from-render-this-usually-me?rq=1
  return(
    <Provider store = {store} >
      <App />
    </Provider>
  )
}

AppRegistry.registerComponent(appName, () => myProvider);

6. 修改 对应的页面文件: ReduxDemo.js

import React,  { Component} from 'react';
import {Image, Platform, StyleSheet, Text, View, Button} from 'react-native'

// 1. 导入相关的文件
import {connect } from 'react-redux'
import {increaseCount} from '../redux_demo/action_creators'

class ReduxDemo extends Component{

  // 4. 定义被触发的事件。
  clickButton = () => {
    // 4.1 该方法来自于下面的 mapDispatchToProps
    // 在 6.2 步骤中
    this.props.increaseCountByOne()
  }

  render(){
    return(
      <View>
        <Text>本例子演示Redux在React Native中的使用: 保存数据和状态。 {"\n"}
        1. 点击之后,计数器 + 1 {"\n"}

        </Text>
        { /* 3. 在 View中增加对应的事件。 */}
        <Button
          title="点击计数!"
          onPress={this.clickButton}
          />
        <Text>
          您点击了:{this.props.count}  {"\n"} (请使用 根目录下的 "AppWithRedux.js "进入到本页面。 否则页面看不到效果。(只能在console 中看到效果) )
        </Text>
      </View>
    )
  }
}

// 5. 把state 映射到 props中。
const mapStateToProps = state => {
  return {
    // 5.1 务必注意,这里是 store.countReducer.count  不是 state.count
    // 没有为什么,把他背下来。
    count: state.countReducer.count
  }
}
// 6. 把 dispatch 映射到 props中
const mapDispatchToProps = dispatch => {
  return {
    // 6.1 定义了一个方法,该方法会在 Component中被调用
    increaseCountByOne: () => {
      // 6.2 increaseCount() 方法来自于 action_creators.js中定义的
      dispatch(increaseCount())
    }
  }
}

// 7. 让上面两个映射生效。  废代码,没意义,但是没它不行。 就得这样写。
export default connect(mapStateToProps, mapDispatchToProps)(ReduxDemo)

这个时候,就可以在Android console 中看到效果了。 (数据已经被保存)

12-29 16:52:46.418 2502-3671/com.hello I/ReactNativeJS: '== count: ', 0
12-29 16:52:47.079 2502-3671/com.hello I/ReactNativeJS: '== count: ', 1
12-29 16:52:47.273 2502-3671/com.hello I/ReactNativeJS: '== count: ', 2
12-29 16:52:47.418 2502-3671/com.hello I/ReactNativeJS: '== count: ', 3
12-29 16:52:47.584 2502-3671/com.hello I/ReactNativeJS: '== count: ', 4
12-29 16:52:47.715 2502-3671/com.hello I/ReactNativeJS: '== count: ', 5

在页面上也 可以看到,每点击一下, 数字就+1

Back