React Native 开发豆瓣评分(三)集成 Redux

什么是 redux

redux 是一个用于管理 js 应用状态(state)的容器。比如组件 A 发生了变化,组件 B 要同时做出响应。常见的应用场景就是用户的登录退出操作:未登录状态,个人中心显示登录按钮,在登录页面进行了登录后,需要在个人中心页面做出相应,显示个人信息。类似的产品有: vuex、flux、dva、mobx。

redux 常见为三个部分:

  • Action:存放改变 Store 内容的方法,想要改变 Store 里面的数据,只能触发 Action 里面的相关方法;
  • Reducer:根据 Action 操作做出不同的响应,返回一个新的 Store;
  • Store:储存数据。

在本应用里使用 redux 主要用于保存用户状态、保存首页数据。

在 React Native 里面使用 redux

安装相关依赖

yarn add redux redux-persist react-redux
  • redux 、react-redux:用于存储应用状态;
  • redux-persist:用于离线存储状态,退出应用后再次进入应用,状态任然存在。

编辑 Action

在 src 目录下创建 action 目录,目录中创建 index.js。

这里创建 2 个应用中要用到的方法,login(登录)、logout(退出);2 个测试 redux 是否生效的方法,add(加大数字)、cut(减少数字)。

export function add(num) { // 每个函数的返回值里面必须得有一个type值,Reducer就是根据type值改变做出相应
    return {
        type: 'add',
        value: ++num
    }
}

export function cut(num) {
    return {
        type: 'cut',
        value: --num
    }
}

export function login(data) {
    return {
        type: 'login',
        data
    }
}

export function logout(data) {
    return {
        type: 'logout',
        data
    }
}

编辑 Reducer

在 src 目录下创建 reducer 目录,目录中创建 index.js/num.js/user.js。

index.js

import { combineReducers } from 'redux';
import num from './num';
import user from './user';

//这里返回的combineReducers()就是 Store 的内容,后面想要获得的话,就是使用 store.user、store.num来获得对应store的数据
export default combineReducers({
    num: num,
    user: user
})

num.js

const initState = {//初始化state内容
    value: 0
}

const setNumState = (state = initState, action) => {
    switch (action.type) {//根据type的不同做出不同的响应
        case 'add':
            return {
                ...state,
                value: action.value,
                status: 'add'
            }
        case 'cut':
            return {
                ...state,
                value: action.value,
                status: 'cut'
            }
        default://必须得有default,用于返回非期望的状态
            return state;
    }
}

export default setNumState;

user.js

const initState = {
    isLogin: false,
    userData: {}
}

const setUserState = (state = initState, action) => {
    switch (action.type) {
        case 'login':
            return {
                ...state,
                isLogin: true,
                userData: action.data
            }
        case 'logout':
            return initState;
        default:
            return state;
    }
}

export default setUserState;

编辑 Store

在 src 目录下创建 store 目录,目录中创建 index.js。

import { AsyncStorage } from 'react-native';
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import hardSet from 'redux-persist/lib/stateReconciler/hardSet';
import reducer from '../reducer';

//配置redux-persist,但下次进入应用,就会从root里面获得数据
let persistConfig = {
    key: 'root',
    storage: AsyncStorage,
    stateReconciler: hardSet
}
const persistedReducer = persistReducer(persistConfig, reducer);
export default function configureStore() {
    const store = createStore(persistedReducer);
    let persistor = persistStore(store);
    return { store, persistor };
}

修改 App.js

import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import configureStore from './store';
import Router from './router';

const store = configureStore();

export default class App extends Component {
  render() {
    return (
      <Provider store={store.store} style={{ flex: 1 }}>
        <PersistGate loading={null} persistor={store.persistor}>
          <Router />
        </PersistGate>
      </Provider>
    );
  }
};

修改 pages 里面的 index.js detail.js 以测试 redux 是否生效

import React from "react";
import { View, Text } from "react-native";
import { connect } from 'react-redux';
import { add, cut } from '../action';


class Home extends React.Component {
  render() {
    const { dispatch, value, navigation } = this.props;
    return (
      <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
        <Text onPress={() => navigation.push('Detail')}>Home Click Me</Text>
        <View style={{ flexDirection: 'row',  300, justifyContent: 'space-around' }}>
          <Text onPress={() => dispatch(add(value))} style={{ backgroundColor: 'blue', color: '#fff', fontSize: 18 }}>减少数字</Text>
          <Text style={{ fontSize: 20 }}>{value}</Text>
          <Text onPress={() => dispatch(cut(value))} style={{ backgroundColor: 'blue', color: '#fff', fontSize: 18 }}>加大数字</Text>
        </View>
      </View>
    );
  }
}

const select = (store) => {
  return {
    value: store.num.value,
  }
}

export default connect(select)(Home);

效果图:

React Native 开发豆瓣评分(三)集成 Redux

这里是一个集成了 router、redux、icons的基本工程,clone下来就能使用 https://github.com/hulinNeil/react-native-base;