redux-persists无法与React Native App一起使用

时间:2018-12-19 13:53:53

标签: javascript react-native redux redux-persist

问题

重新启动应用程序时,存储没有保留或以某种方式被重置

预期行为

该应用程序基本上只有一个登录表单,其中触发了一些还原操作。例如,用户名和密码都会保存到商店中。

在使用Reactotron进行检查之后,商店实际上按照预期的方式进行了开发,用户名和密码以及其他字段均已更新。

技术栈

使用Redux响应本机应用(不是Expo)

package.json

"dependencies": {
    "react": "16.6.1",
    "react-native": "0.57.7",
    "react-native-gesture-handler": "^1.0.12",
    "react-native-i18n": "^2.0.15",
    "react-navigation": "^3.0.8",
    "react-redux": "^6.0.0",
    "redux": "^4.0.1",
    "redux-persist": "^5.10.0"
  },

申请状态

我已经创建了一个简单的ReactNative应用,其中根组件为:

App.js

import React, {Component} from 'react';
import { Provider } from 'react-redux';
import LoadingIndicator from '@components/Visual/LoadingIndicator/';
import MainNavigator from '@components/Visual/MainNavigator'
import {checkUserState} from '@actions/GlobalActions'
import {store, persistor} from '@components/Storage/StorageConfigurationBuilder'
import { PersistGate } from 'redux-persist/integration/react'

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

  componentDidMount() {
    store.dispatch(checkUserState())
  }

  render() {
    return (
        <Provider store={store}>
          <PersistGate loading={<LoadingIndicator />} persistor={persistor}>
              <MainNavigator initialRoute={this.props.initialRoute} />
          </PersistGate>
        </Provider>
    );
  }
}
导入中的

@components@actions由babel插件“ module-resolver”解决。

.babelrc

...
["module-resolver", {
      "root": ["."],
      "alias": {
        "^@constants/(.+)": "./constants/\\1",
        "@i18n": "./i18n/index.js",
        "^@components/(.+)": "./components/\\1",
        "^@screens/(.+)": "./screens/\\1",
        "^@reducers/(.+)": "./reducers/\\1",
        "^@actions/(.+)": "./actions/\\1",
      }
    }]
...

在同时提供商店和持久性的路线应用程序中导入的StorageConfigurationBuilder很简单:

StorageConfigurationBuilder.js

import { createStore } from 'redux'
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage/index.native'
import AllReducers from '@reducers/AllReducers'
//import Reactotron from '../../ReactronConfig'

const persistConfig = {
    key: 'root',
    storage
}
const persistedReducer = persistReducer(persistConfig, AllReducers)

export const store = createStore(persistedReducer)
export const persistor = persistStore(store)

最后,将要呈现的视图组件分为两部分

index.js

import React, {Component} from 'react'
import { connect } from 'react-redux';
import LoginView from './LoginView';
import {loginFetch, loginFetchError, loginFetchSuccess} from '@actions/UserActions'
import ApiConfiguration, { getApiBaseUri } from '@constants/ApiConfiguration'

class LoginController extends Component {
    constructor(props) {
        super(props)
    }

    doLogin() {
      this.props.dispatch(loginFetch());

      fetch(getApiBaseUri() + ApiConfiguration.endpoints.authentication.path, {
          ...ApiConfiguration.headers,
          method: ApiConfiguration.endpoints.authentication.method,
          body: JSON.stringify({
            email: this.props.email, 
            password: this.props.password
          })
        }).then((response) => {
          return response.json()
        }).then((response) => {
          this.props.dispatch(loginFetchSuccess(response))
        }).catch((e) => {
          this.props.dispatch(loginFetchError(e))
        })
    }

    render() {
        return <LoginView {...this.props} login={this.doLogin.bind(this)} />;
    }
}

const mapStateToProps = (state) => {
    const { user } = state
    return { user }
};

export default connect(mapStateToProps)(LoginController);

视图<LoginView />本身没有什么特别之处

LoginView.js

import React from 'react';
import {StyleSheet, SafeAreaView, View, TextInput, Text, TouchableOpacity} from 'react-native';
import {changeEmail, changePassword} from '@actions/UserActions'
import I18n from '@i18n';
import Colors from '@constants/Colors';

export default props => {
    return (<SafeAreaView style={styles.container}>
        <View style={styles.loginForm}>

            <View style={styles.fieldContainer}>
                <Text style={styles.fieldLabel}>{I18n.t('login.email_label')}</Text>
                <TextInput 
                    value={props.user.email}
                    onChangeText={value => props.dispatch(changeEmail(value))}
                    placeholder={I18n.t('login.email_placeholder')} 
                    style={styles.field} 
                    textContentType={"username"} 
                    returnKeyType={"next"}
                    underlineColorAndroid={"transparent"}></TextInput>
            </View>

            <View style={styles.fieldContainer}>
                <Text style={styles.fieldLabel}>{I18n.t('login.password_label')}</Text>
                <TextInput 
                    value={props.user.password}
                    onChangeText={value => props.dispatch(changePassword(value))}
                    style={styles.field}  
                    placeholder={I18n.t('login.password_placeholder')} 
                    textContentType={"password"} 
                    underlineColorAndroid={"transparent"}
                    secureTextEntry={true}></TextInput>
            </View>

            <View style={styles.panelFooter}>
                <TouchableOpacity onPress={() => props.login()}>
                    <Text>
                        {I18n.t('login.login_button')}
                    </Text>
                </TouchableOpacity>
            </View>
        </View>
    </SafeAreaView>);
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: Colors.backgroundColor,
        justifyContent: 'center'
    },
    loginForm: {
        marginLeft: 20,
        marginRight: 20,
        justifyContent: 'space-around',
        borderWidth: 1,
        borderColor: Colors.borderColor,
        borderRadius: 5
    },

    panelFooter: {
        flexDirection: 'row',
        justifyContent: 'flex-end',
        backgroundColor: '#e5e5e5',
        height: 44,
        paddingRight: 20,
        paddingTop: 13,
        marginTop: 35
    },

    fieldContainer: {
        height: 50,
        flexDirection: 'column',
        marginLeft: 20,
        marginRight: 20,
        marginTop: 25
    },
    fieldLabel: {
        fontSize: 13,
        fontWeight: "600",
        marginBottom: 4,
        marginLeft: 10
    },
    field: {
        height: 44,
        borderWidth: 1,
        borderColor: Colors.borderColor,
        borderRadius: 22,
        fontSize: 18,
        paddingLeft: 22,
        paddingRight: 10
    }
})

1 个答案:

答案 0 :(得分:0)

因此,我添加了一个简单的reducer / action并将其附加到我的应用程序中,即与上述相同的应用程序。我从先前创建的另一个standalone project处获得了此代码,效果很好。

在这部分中,FriendReducer继续正常工作,而上述我的减速器仍无法正常工作。

最后,我在reducer中添加了以下情况以恢复我的应用程序状态。由于某种原因,它不是自己做的。

case 'persist/REHYDRATE':
   //rehydrating userStore to app
   newState = { ...action.payload.userStore }
   return newState