score:0

i would update your code and split it into two components, a list component and an item component (in this case pizza?). the list component would provide a method for modifying the list using the context api. in my example, i have an updatepizza method that i pass down in the context.

then, in the child component, you have a click handler that updates the occupied status of the pizza and tells the parent what the new status is using the context method.

this makes sure that the parent component always has the current state for all the pizzas and passes that down to the children. the parent component becomes the single source of truth here.

class list extends react.component {
  static childcontexttypes = {
    updatepizza: react.proptypes.func
  }

  constructor({ pizzas }){
    super()
    this.state = { pizzas }
  }

  updatepizza = (idx, pizza) => {
    this.setstate( ({ pizzas }) => {
      pizzas[idx] = pizza;
      return { pizzas }
    })
  }

  getchildcontext() {
    return { updatepizza: this.updatepizza }
  }

  render(){
    return <ul>{this.state.pizzas.map((pizza, idx) => <pizza key={ idx } { ...pizza }>)}<ul>
  }
}

class pizza extends react.component {
  static contexttypes = {
    updatepizza: react.proptypes.func
  }

  handleclick = () => {
    this.state.occupied = !this.state.occupied;
    this.context.updatepizza(this.state.key, this.state)
  }

  render() {
    const { key, seat, row, occupied } = this.state;
    const status = occupied ? 'coloring' : 'colored';
    return <li key={ key } classname={ status } onclick={ handleclick }> seat: { seat } { row }</li>
  }
}

score:1

i created a simple example of how you can update your code, also with two components (similar to the idea by @thethechad), but without using context since according to react docs it is discouraged to use context directly if you want your app to be stable. if state and props management in app gets too complicated you can include redux (which internally also uses context), but for now i am not including redux since it be might over-complication in this simple case.

here is pizzalist which has pizzas on its state. the component will render pizzaitem components and pass a callback down so that each pizzaitem can notify its parent (pizzalist) when it is clicked. pizzalist has the responsibility of toggling pizzaitem when it is clicked.

class pizzalist extends react.purecomponent {
    state = {
      pizzas: []
    }
    componentdidmount() {
      // fetch data about pizzas via an api and perform this.setstate
      this.setstate({ pizzas: [{ seat: 20, occupied: false }, { seat: 10, occupied: true }, { seat: 30, occupied: true }] });
    }
    handlepizzaitemclick = (pizzaind) => {
      this.setstate((prevstate) => {

        // find clicked pizza and toggle its occupied property
         const pizzas = prevstate.pizzas.map((pizza, ind) => {
            if (ind === pizzaind)
               return { ...pizza, ...{ occupied: !pizza.occupied } };

            return pizza;
         });

        return { pizzas: pizzas };
      });
    }
    render () {
        return (
            <ul>
              {this.state.pizzas.map((pizza, index) => 
                <pizzaitem 
                  onclick={this.handlepizzaitemclick} 
                  index={index} 
                  pizza={pizza}
                />)}
            </ul>
        );
    }
}

pizzaitem is a simple function component that doesn't have any state.

const pizzaitem = ({ index, pizza, onclick }) => {
    const { seat, row, occupied } = pizza;
    const pizzaclassname = occupied ? 'coloring' : 'colored';

    return (
      <li key={index} 
        classname={pizzaclassname} 
        onclick={() => onclick(index)}> 
        seat: {seat} {row}
      </li>
    );
}

here is a working example on codesandbox.


Related Query

More Query from same tag