Reputation: 47
I'm trying to make a list of star wars movies I have watched. I want to have the capability to check and uncheck what I clicked and have it saved by localStorage. For some reason, sometimes, if I cross more than one movie at a time, after I refresh the page, only the last one i crossed remains crossed. I tried to debug with my console, and I see that the fault is with my state. Sometimes, after I click more than one element, some of them will stay false, instead of turning true.
this is my code:
import React from 'react';
export default class Movie extends React.Component{
constructor(props){
super()
this.state = (localStorage.appState) ? JSON.parse(localStorage.appState)
: { 0: false, 1: false, 2: false, 3: false, 4: false, 5: false};
}
clickedTitle = (event) => {
if (event.target.tagName === "SPAN") {
this.setState({
[event.target.id]: !this.state[event.target.id]
}, () => {
localStorage.setItem('appState',JSON.stringify(this.state))
});
// localStorage.clear()
}
}
render(){
return(
<div className="sw_title" onClick={this.clickedTitle}>
<span id={this.props.index} className={`${this.state[this.props.index] ? "clicked" : "not-clicked"}`}> {this.props.title} </span>
</div>
);
}
}
Thanks in advance for your precious time! April
Upvotes: 1
Views: 65
Reputation: 620
As far as I am able to tell you are doing this on each singular Movie element. Being that every time you set the same localStorage Item to a new value of a single movie (being your state for given Movie component only holds value for one instance). It would be a better practice to keep state management outside Movie component, say in MovieS and only do presentational work in a Movie
import React from 'react';
export default class MovieS extends React.Component{
constructor(props){
super(props)
this.state = (localStorage.appState) ? JSON.parse(localStorage.appState)
: { 0: false, 1: false, 2: false, 3: false, 4: false, 5: false};
}
clickedTitle = (event) => {
if (event.target.tagName === "SPAN") {
this.setState({
[event.target.id]: !this.state[event.target.id]}, () => {localStorage.setItem('appState', JSON.stringify(this.state))
});
// localStorage.clear()
}
}
render(){
this.props.movies.map( (movie) => (
<Movie
click={clickedTitle}
className={this.state[movie.id] ? "clicked" : "not-clicked"}
title={movie.title}
/>
))
}
}
function Movie({ click, className, title }) => (
<div className="sw_title" onClick={click}>
<span id={this.props.index} className={}> {} </span>
</div>
)
Upvotes: 0
Reputation: 4873
There should be a single "source of truth" for any data that changes in a React application and you are repeating appState
in every Movie component which leads to inconsistent app state.
What you should do is to lift the state up. In other words, move that state and clickedTitle
function to their parent component and pass clickedTitle
as a prop to the Movie Component. (or you could use Context)
More about Lifting State Up
Upvotes: 1