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
}
}
Your App component is not subscribing to the store and so it does not re-render when the store changes (i.e. it will only use the first name value returned from store.getState()
To fix you could use react-redux to connect to the store instead of passing it as a prop.
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);
Alternatively you can more add a render() call inside the subscribe callback in src/index.js
// ...
store.subscribe(() => {
saveState(store.getState());
render();
});
function render () {
ReactDOM.render(<App store={store}/>, document.getElementById('root'));
registerServiceWorker();
}
render();
although you might want to do something else with the registerServiceWorker() call.
Side Note: have you tried redux-persist?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With