Reputation: 371
I'm having a problem with a component that gets data from an array in localstorage. It gets the initial data when the page loads, but how do I update when localstorage is changed?
import React, {Component} from 'react';
class MovieList extends Component {
constructor(props){
super(props)
this.state = {
filmList: []
}
}
componentWillMount(){
var film = [],
keys = Object.keys(localStorage),
i = keys.length;
while ( i-- ) {
film.push( localStorage.getItem(keys[i]))
}
this.setState({filmList: film})
};
render(){
return(
<ul>
<li>{this.state.filmlist}</li>
</ul>
);
}
}
export default MovieList;
Upvotes: 27
Views: 35071
Reputation: 65
import React, { Component } from "react";
import { Subject, share } from "rxjs";
export default class StorageService extends Component {
constructor() {
super();
this.start();
this.onSubject = new Subject();
this.changes = this.onSubject.asObservable().pipe(share());
}
componentWillUnmount() {
this.stop();
}
getStorage() {
let s = [];
for (let i = 0; i < localStorage.length; i++) {
s.push({
key: localStorage.key(i),
value: JSON.parse(localStorage.getItem(localStorage.key(i))),
});
}
return s;
}
store(key, data) {
localStorage.setItem(key, JSON.stringify(data));
this.onSubject.next({ key: key, value: data });
}
clear(key) {
localStorage.removeItem(key);
this.onSubject.next({ key: key, value: null });
}
start() {
window.addEventListener("storage", this.storageEventListener.bind(this));
}
storageEventListener(event) {
if (event.storageArea === localStorage) {
let v;
try {
v = JSON.parse(event.newValue);
} catch (e) {
v = event.newValue;
}
this.onSubject.next({ key: event.key, value: v });
}
}
stop() {
window.removeEventListener("storage", this.storageEventListener.bind(this));
this.onSubject.complete();
}
render() {
return <div>StorageService</div>;
}
}
// import it where you needed and subscribe
const newStorageService = new StorageService();
newStorageService.changes.subscribe((localStoreObject) => {
// do whatever yo want
})
Upvotes: 1
Reputation: 2391
For anyone stumbling upon this question, the answer to "how to listen to localStorage changes" can be found here: https://developer.mozilla.org/en-US/docs/Web/API/StorageEvent
Upvotes: 10
Reputation: 1186
Per Mozilla's Web API docs there's a StorageEvent
that gets fired whenever a change is made to the Storage
object.
I created an Alert component within my application that would go off whenever a change was made to a specific localStorage
item. I would've added a code snippet for you to run but you can't access localStorage through it due to cross-origin issues.
class Alert extends React.Component {
constructor(props) {
super(props)
this.agree = this.agree.bind(this)
this.disagree = this.disagree.bind(this)
this.localStorageUpdated = this.localStorageUpdated.bind(this)
this.state = {
status: null
}
}
componentDidMount() {
if (typeof window !== 'undefined') {
this.setState({status: localStorage.getItem('localstorage-status') ? true : false})
window.addEventListener('storage', this.localStorageUpdated)
}
}
componentWillUnmount(){
if (typeof window !== 'undefined') {
window.removeEventListener('storage', this.localStorageUpdated)
}
}
agree(){
localStorage.setItem('localstorage-status', true)
this.updateState(true)
}
disagree(){
localStorage.setItem('localstorage-status', false)
this.updateState(false)
}
localStorageUpdated(){
if (!localStorage.getItem('localstorage-status')) {
this.updateState(false)
}
else if (!this.state.status) {
this.updateState(true)
}
}
updateState(value){
this.setState({status:value})
}
render () {
return( !this.state.status ?
<div class="alert-wrapper">
<h3>The Good Stuff</h3>
<p>Blah blah blah</p>
<div class="alert-button-wrap">
<button onClick={this.disagree}>Disagree</button>
<button onClick={this.agree}>Agree</button>
</div>
</div>
: null )
}
}
Upvotes: 21