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', width: 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);
效果图:
这里是一个集成了 router、redux、icons的基本工程,clone下来就能使用 https://github.com/hulinNeil/react-native-base;