2

我已经尝试了一周或更长时间,以使我的状态在反应原生的 Android 应用程序中持续存在,但在重新水化后,状态始终具有初始值。如果我使用 Redux devtools 检查 ASyncStorage 内容或状态,它是初始状态:

{
   "status":"{\"actions\":[]}",
   "list":"{\"actions\":[]}",
   "map":"{\"site_ids\":{},\"alarmCounts\":[],\"geoJSON\":{}}",
   "_persist":"{\"version\":-1,\"rehydrated\":true}"
}

Unexpected key "_persist" ...当我使用 redux-reset 并且无法从 Google 找到任何解决方案时,我也会收到错误消息。

如果我运行store.flush()or store.purge(),我在 ASyncStorage 中看不到任何变化。

我的 configureStore 文件如下。我认为问题出在此处。有什么帮助吗?

import { createStore } from "redux";
import { composeWithDevTools } from 'redux-devtools-extension';
import { persistStore, persistCombineReducers } from "redux-persist";
import reduxReset from 'redux-reset';
import { AsyncStorage } from 'react-native'

import userReducer from '../reducers/user';
import statusReducer from '../reducers/status';
import listReducer from '../reducers/list';
import mapReducer from '../reducers/map';

function reset(): void {
    console.log('Reseting state');
    store.dispatch({
      type: 'RESET'
    });
    // persistor.purge();
};

function flush() {
    console.log('FLUSH');
    persistor.flush();
}

const enhancer = composeWithDevTools(
    reduxReset()
);

const appReducer = persistCombineReducers(
    { // cfg
        key: 'primary',
        storage: AsyncStorage,
        blacklist: ['user'],
        throttle: 1000
    },
    {
        user: userReducer,
        status: statusReducer,
        list: listReducer,
        map: mapReducer
    }
);

const rootReducer = (state, action) => {
  return appReducer(state, action);
}

const store = createStore(
    rootReducer,
    enhancer
);

const persistor = persistStore(store, null);

export default { store, persistor, reset, flush };

我使用 redux@3.7.2、redux-persist@5.9.1、react-native@0.54.0

4

5 回答 5

1

这不是对问题的直接回答,而是为这个问题提供了替代解决方案和一些观点。

我不熟悉 redux-persist 或它的功能,但我自己更喜欢在 redux 中制作自己的中间件。

import initState from "./reducers/InitiateReducer"

let initialState = initState

将数据保存到 LocalStorage 的中间件

const localStoreMiddleware = (store) => (next) => (action) => {
  // Get previously stored state
  const ls = localStorage.getItem("reduxState") || null

  let state = {
    application: {}
  }

  if (ls) {
    state = { ...JSON.parse(ls) }
  }
  // Actions that will be required to save data to localStore
  switch (action.type) {
    case "APP_SESSION":
      state.application.session = { ...action.payload.session }
      break
    case "VERIFICATION_DONE":
      state.application.verification_required = false
      break
  }

  localStorage.setItem("reduxState", JSON.stringify(state))
  next(action)
}

将 LocalStorage 获取到 initialState 变量并传递值

if (localStorage.getItem("reduxState") !== null) {
  const ls = JSON.parse(localStorage.getItem("reduxState")) || {}

  if (ls.application) {
    if (ls.application.session) {
      initialState.application.session = ls.application.session
    }
    initialState.application.verification_required =
      ls.application.verification_required
  }
}

使用 initialState 创建存储变量

const store = () => {
  return createStore(
    rootReducer,
    initialState,
    applyMiddleware(
      thunkMiddleware,
      localStoreMiddleware
    )
  )
}

export default store

此功能是使用浏览器的 localStorage 实现的,但可以在 React Native 和使用 asyncStorage 中使用相同的思想。然后,您只需包装您喜欢 connect() 的组件并在您想要的变量上使用 mapStateToProps 。

很抱歉没有提供 React Native 就绪的解决方案,我自己会在周末更深入地讨论这个问题。

于 2018-04-06T14:47:59.650 回答
0

尝试以AsyncStorage这种方式坚持:

persistStore(store, {storage: AsyncStorage})
于 2018-04-06T17:44:25.567 回答
0

我变了:

const store = createStore(
    persistReducer,
    enhancers
);

至:

const store = createStore(
    persistReducer,
    undefined,
    enhancers
);

现在,如果我执行 store.flush() 它会持续存在,但不会在每次状态更改时自动执行。它在应用程序状态更改时刷新(前景/背景)。

于 2018-04-09T07:35:18.610 回答
0

这是一个简单的示例,您可以在每次单击按钮时查看状态更改后更改的 AsyncStorage 值:

import PropTypes from 'prop-types'
import React, { Component } from 'react';
import { applyMiddleware, compose, createStore } from 'redux'
import { AsyncStorage, AppRegistry, Button, StyleSheet, Text, View } from 'react-native';
import { combineReducers, Provider, connect } from 'react-redux'
import { persistStore, persistCombineReducers, autoRehydrate} from 'redux-persist'
import thunk from 'redux-thunk';

class Counter extends Component {
    render() {
        const { value, onIncreaseClick,  checkValueInStorage} = this.props
        return (
            <Text>
                <Text>Val: {value}</Text>
                <Button title="Increase" onPress={() => {
                    onIncreaseClick()
                    checkValueInStorage()
                }}/>
            </Text>
        )
    }
}

Counter.propTypes = {
    value: PropTypes.number.isRequired,
    onIncreaseClick: PropTypes.func.isRequired
}

const increaseAction = { type: 'increase' }

function counter(state = { count: 0 }, action) {
    const count = state.count
    switch (action.type) {
        case 'increase':
            return { count: count + 1 }
        default:
            return state
    }
}

const allReducers = {
    counter: counter
};

const persistConfig = {
    key: 'primary',
    storage: AsyncStorage
}

const persistedReducer = persistCombineReducers(persistConfig, allReducers)

const rootReducer = (state, action) => {
    return persistedReducer(state, action);
}
let store = createStore(rootReducer, undefined, applyMiddleware(thunk))
let pers = persistStore(store, null)


function mapStateToProps(state) {
    return {
        value: state.counter.count
    }
}

function mapDispatchToProps(dispatch) {
    return {
        onIncreaseClick: () => dispatch(increaseAction),
        checkValueInStorage: () => {
            AsyncStorage.getItem("persist:root").then(function (specifiVal) {
                console.log("persist:root: Value before delay" + JSON.stringify(specifiVal))
            })

            setTimeout(function () {
                AsyncStorage.getItem("persist:root").then(function (specifiVal) {
                    console.log("Value after delay" + JSON.stringify(specifiVal))
                })
            }, 5000);

        }
    }
}

const AppCounter = connect(
    mapStateToProps,
    mapDispatchToProps
)(Counter)

export default class App extends React.Component {
    render() {
        return (
            <Provider store={store}>
                <View style={styles.container}>
                    <Text>Counter view</Text>
                    <AppCounter/>
                </View>
            </Provider>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#fff',
        alignItems: 'center',
        justifyContent: 'center'
    }
});
于 2018-04-09T22:22:33.413 回答
0

轻松修复

用值指定stateReconcilerhardSet

import hardSet from "redux-persist/es/stateReconciler/hardSet";

...
...


const appReducer = persistCombineReducers(
    { // cfg
        key: 'primary',
        storage: AsyncStorage,
        blacklist: ['user'],
        throttle: 1000,
        stateReconciler: hardSet
    },
    {
        user: userReducer,
        status: statusReducer,
        list: listReducer,
        map: mapReducer,
        stateReconciler: hardSet
    }
);
于 2019-06-02T19:22:35.263 回答