2
votes

I created a sample React Native app to see if I can get Redux-persist working. However my React Native app with Redux Persist is not saving state to persisted storage.

Every time i change the toggle to 'true' and then reload the app, the state is not persisted and goes back to null.

How can I get 'True' to stay persisted when I refresh the app.

Here is my code:

index.js:

import {AppRegistry} from 'react-native';
import {name as appName} from './app.json';
import React, {Component} from 'react';
import { Provider } from "react-redux";
import { store, persistor } from "./Store/index";
import { PersistGate } from 'redux-persist/integration/react'
import App from './App.js';

class ReduxPersistTest extends Component {

render() {
  return (
    <Provider store={store}>
      <PersistGate persistor={persistor} loading={null}>
      <App />
      </PersistGate>
    </Provider>
          );
        }
      }

AppRegistry.registerComponent('ReduxPersistTest', () => ReduxPersistTest);

store/index.js:

import { createStore, applyMiddleware, compose } from "redux";
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import toggle from "../Reducers/rootReducer.js";

import { AsyncStorage } from "react-native";
import {persistStore, persistReducer, persistCombineReducers} from "redux-persist";
import storage from 'redux-persist/lib/storage'
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';

const togglePersistConfig = {
  key: 'toggle',
  storage: AsyncStorage
};

const middleware = [thunk];

const persistConfig = {
  key: 'root',
  storage: AsyncStorage,
  debug: true,
  whitelist: ['toggle']
}

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const reducers = { toggle: persistReducer(togglePersistConfig, toggle) };
const persistedReducer = persistCombineReducers(persistConfig, reducers);


export const store = createStore(
  persistedReducer, composeEnhancers(applyMiddleware(...middleware))
);


export const persistor = persistStore(store);

Reducer.js

The issue might be found here in my reducer...

import { ADD_TOGGLE } from "../Constants/action-types";

import { combineReducers } from 'redux';


const initialState = {
  toggle: false,
};

const rootReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_TOGGLE:
    console.log(action.payload.toggle);
    console.log(action.payload);
    return {
      ...state, toggle: {
        toggle: action.payload.toggle,
    }};
    default:
      return state;
  }
};


export default rootReducer;

Actions/index.js

import { ADD_TOGGLE } from "../Constants/action-types";

export const addToggle = toggle => ({ type: ADD_TOGGLE, payload: toggle });

Constants/action-Types.js

export const ADD_TOGGLE = "ADD_TOGGLE";

And my components:

App.js

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

import Copy from './Components/Copy/Copy.js';
import CopyToggle from './Components/Copy/CopyToggle.js';

/*
Redux imports
*/
import { connect } from "react-redux";
import { addToggle } from "./Actions/index";

/*
Redux constants
*/
const mapDispatchToProps = dispatch => {
  return {
    addToggle: toggle => dispatch(addToggle(toggle))
  };
};

//Styles
const styles = StyleSheet.create({
  textHeader: {
    textAlign: 'center',
    marginBottom: 10,
    marginTop: 100,
  },
});

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
          toggle: false,
        };
  }

  componentWillMount() {
    const { toggle } = this.state;
    this.props.addToggle({ toggle });
  }

render() {
  return (
    <View>
      <Text style={styles.textHeader}>Welcome to React Native!</Text>
      <Copy />
      <CopyToggle />
    </View>
        )
      }
    }

export default connect(null, mapDispatchToProps)(App);

Copy.JS (toggle UI to change the toggle value from 'true' to 'false'

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

    import { compose } from 'react-compose';
    import { Switch } from 'react-native-switch';

    import { connect } from "react-redux";
    import { addToggle } from "../../Actions/index";

    const mapDispatchToProps = dispatch => {
      console.log('mapDispatchToProps hit');
      return {
        addToggle: toggle => dispatch(addToggle(toggle))
      };
    };


    class Copy extends Component {
      constructor(props) {
        super(props);

        this.state = {
          toggle: false,
        };

        this.addtoggle = this.addtoggle.bind(this);

      }

      addtoggle(val) {
        this.setState({
          toggle: val,
        }, function () {
          const { toggle } = this.state;
          this.props.addToggle({ toggle });
        });
      }


      render() {
        return (
            <View>
              <Text>Test redux persist</Text>
              <Switch
      value={ this.state.toggle }
      onValueChange={(val) => this.addtoggle(val)}
    />
            </View>
        );
      }
    }

    export default connect(null, mapDispatchToProps)(Copy);

CopyToggle.js (outputs the boolean value of the toggle)

import React, { Component } from 'react';

/*
Redux imports
*/
import { connect } from "react-redux";
import { addToggle } from "../../Actions/index";

/*
Native base and react native
*/
import { StyleSheet, View, Text } from 'react-native';

/*
Redux constants
*/
const mapDispatchToProps = dispatch => {
  return {
    addToggle: toggle => dispatch(addToggle(toggle))
  };
};

const mapStateToProps = state => {
  return { toggle: state.toggle.toggle };
};

// Custom Styles
const styles = StyleSheet.create({
  textHeader: {
    color: '#000',
  },
});


//class
class CopyToggle extends Component {
  constructor(props) {
    super(props);
      this.state = {
        purchase: false,
      };
this.toggleDisplay = this.toggleDisplay.bind(this);
  }

  componentWillMount() {
    const { toggle } = this.state;
    this.props.addToggle({ toggle });
  }

//display to output bollean value
  toggleDisplay() {
    let toggleState;
    if (this.props.toggle === false) {
      toggleState = 'false'
    }
    else if (this.props.toggle === true) {
      toggleState = 'true'
    }
    return (
      <Text>{toggleState}</Text>
    )
  }

//render
  render() {
    return (
      <View>
        {this.toggleDisplay()}
      </View>
    );
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(CopyToggle);

It would be greatly appreciated id someone with knowledge on Redux persist can review and hopefully point out my issue.

THanks!

2

2 Answers

1
votes

You need to use persistCombineReducers if you want to persist just part of your store, so I would come up with something similar to this:

import { persistCombineReducers, persistReducer } from 'redux-persist';

import toggle from './Reducer.js';

const togglePersistConfig = {
  key: 'toggle',
  storage: AsyncStorage
};

const reducers = {
  toggle: persistReducer(togglePersistConfig, toggle),
  // ...other reducers
}

const persistConfig = {
  key: 'root',
  storage: AsyncStorage,
  debug: true,
  whitelist: ['toggle']
};

const persistedReducer = persistCombineReducers(persistConfig, reducers);

export const store = createStore( persistedReducer, composeEnhancers(applyMiddleware(...middleware)) );
0
votes

You have to add the value you want to persist in the storage object:

AsyncStorage.setItem('toggle': this.state.toggle)