1

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

2 Answers 2

1

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

0

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>
)

Not the answer you're looking for? Browse other questions tagged or ask your own question.