首页 > 解决方案 > React: redux persistence in local storage

问题描述

I'm trying out persisting data to localstorage with Redux. I just made an array of alphabet letter. Whenever I click the element with the onclick listener, I see the console log statement with a random letter each time but the UI doesn't re-render as it would with a setState() call, until I refresh the page. What am I missing here?

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import {createStore} from 'redux';
import myApp from './reducers';

import {loadState, saveState} from './localStorage'


const persistedState = loadState();

const store = createStore(
    myApp,
    persistedState
);

store.subscribe(() => {
    saveState(store.getState());
});

function render () {
    ReactDOM.render(<App store={store}/>, document.getElementById('root'));
    registerServiceWorker();
}

render();

src/app.js

import React, { Component } from 'react';
import './App.css';
import { switchName } from './actions'

class App extends Component {

  constructor(props) {
    super(props);
    this.store = this.props.store;
  }

  handleChangeName = () => {
    let array = ["a","b","c","d","e","f","g","h","i"];
    const data = array[Math.floor(Math.random() * array.length)];
    this.store.dispatch(switchName(data));
  }



  render() {
    return (
      <div className="App">

        <p className="ntro" onClick = {this.handleChangeName} >
          Letter:  {this.store.getState().name}
        </p>
      </div>
    );
  }
}

export default App;

src/localstorage.js

export const loadState = () => {
    try {
        const serializedState = localStorage.getItem('state');
        if (serializedState === null) {
            console.log("serialzed state null")

            return undefined;
        }
        return JSON.parse(serializedState);
    } catch (err) {
        return undefined;
    }
};


export const saveState = (state) => {
    try {
        console.log(state)
        const serializedState = JSON.stringify(state);
        localStorage.setItem('state', serializedState);

    } catch (err) {};
}   

src/reducers.js

const initialState = {
    name: "nada"
}

export default (state = initialState, action) => {
    switch (action.type) {
        case "SWITCH_NAME":
            return Object.assign({}, state,{
                name: action.data
            })

        default:
            return state

    }
}

标签: javascriptreactjsredux

解决方案


您的App组件没有订阅商店,因此当商店更改时它不会重新渲染(即它只会使用name从返回的第一个值store.getState()

要修复,您可以使用react-reduxtoconnect到商店而不是将其作为道具传递。

src/index.js

import { Provider } from 'react-redux';

// ...

function render () {
    ReactDOM.render(<Provider store={store}><App store={store}/></Provider>, document.getElementById('root'));
    registerServiceWorker();
}

src/app.js

import { connect } from 'react-redux'

// ...

class App extends Component {

  handleChangeName = () => {
    let array = ["a","b","c","d","e","f","g","h","i"];
    const data = array[Math.floor(Math.random() * array.length)];
    this.props.switchName(data);
  }

  render() {
    return (
      <div className="App">

        <p className="ntro" onClick = {this.handleChangeName} >
          Letter:  {this.props.name}
        </p>
      </div>
    );
  }
}

// note that `store` is no longer used inside the `App` component

const mapState = state => ({ state.name });
const actions = { switchName };

export default connect(mapState, actions)(App);

或者,您可以render()subscribe回调中添加更多调用src/index.js

// ...

store.subscribe(() => {
    saveState(store.getState());
    render();
});

function render () {
    ReactDOM.render(<App store={store}/>, document.getElementById('root'));
    registerServiceWorker();
}

render();

尽管您可能想对registerServiceWorker()通话做其他事情。


旁注:你试过redux-persist吗?


推荐阅读