0

I am trying to toggle a class in React (only in the else statement).

class Inf extends React.Component {

    constructor() {
      super();
      this.state = {
        pizzaData: data
    }
    }
    renderList(info){
      const list = this.state.pizzaData.map((entry, index) => {
              if (entry.occupied==true){
               return <li class="coloring" key={index}>Seat: {entry.seat}{entry.row}</li>;
             }
             else{
               return <li class="colored" key={index}>Seat: {entry.seat}{entry.row}</li>;
             }
           });
           return(
               <ul>{list}</ul>
           )
  }

Now, looking over some of the documentation I was unsure how to do this. I know that there needs to be a "toggle" on the li and (I think) something like this below the this.state={:

pizzaData:data
},
handleClick function(

But I am not sure.

4
  • Yes, you need a click handler. What is your goal, from a responsive standpoint? Do you want to click the <li/> and have it toggle itself? Commented Dec 31, 2017 at 21:15
  • Yes that's right. Basically if the user selects an li in the else statement it will change the corresponding li's color. Commented Dec 31, 2017 at 21:18
  • What does the data structure pizzaData look like? Commented Dec 31, 2017 at 21:46
  • It looks something like this: [ { "seat": 20, "occupied": false }, { "seat": 10, "occupied": true } Commented Dec 31, 2017 at 21:53

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

Comments

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

2 Comments

Isn't context something one should avoid using according to the React docs? reactjs.org/docs/context.html
Yes and no. It's still "experimental", meaning they're still refining it (and it's subject to change). That being said, all of the major libraries for React use it (redux, react-router, etc), so it's likely there won't be any breaking changes. If you're still afraid to touch it, your other option is to pass the bound method updatePizza to each child component as a property. The whole goal here is to do the mutation at the parent level and let the changes propagate. You can also use redux, then every component has access to the global state.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.