jakmas
jakmas

Reputation: 93

How can I setState of in a nested array

I was practicing a React and tried to build Arya's kill list. I played around and implemented some features, one supposed to change a person when double clicked. In state I have array (list of people) of array <--- and I want to setState to this array.

I tried to use a ternary operator which suppose to change state from false to true and opposite. But it doesn't work.

Here are examples of a code with solutions I tried to implement:

class App extends React.Component {
  state = {
    toKill: [
      { name: 'Cersei Lannister',
        formDouble: false
      },
      { name: 'Ser Ilyn Payne',
        formDouble: false
      },
      { name: 'The Mountain',
        formDouble: false
      },
      { name: 'The Hound',
        formDouble: false
      }
    ], 
  }

doubleClickHandler = (index) => {
    this.setState({
      toKill: this.state.toKill.map(obj =>
        obj[index].formDouble ? false : true)
    })


    // console.log(this.state.toKill[index].formDouble)
    // this.state.toKill[index].formDouble === false ? 
    // this.setState({
    //   [this.state.toKill[index].formDouble]: true
    // }) : this.setState({
    //   [this.state.toKill[index].formDouble]: false
    // })
  }

(...)

        <div>
          {this.state.toKill.map((toKill, index) => {
          return <ToKill 
            double ={() => this.doubleClickHandler(index)}
            formDouble={toKill.formDouble}
            click ={() => this.deleteToKillHandler(index)}
            key={index + toKill.name}
            name={toKill.name}
            cause={toKill.cause}
            img={toKill.img} />
          })}
        </div>

In doubleClickHandler you can see what I tried to implement and it didn't work.

Here is toKill component:



const ToKill = (props) => {

  return (
    <div className="hero-card" onDoubleClick={props.double}>
    {props.formDouble !== true? <h1>test</h1> 
      : <>
          <div className="hero-img-container">
            <img 
              src={props.img} 
              alt={props.name}
              className="hero-img"
            />
          </div>
          <div className="hero-desc">
            <h3 className="hero-name">{props.name}</h3>
            <p className="hero-cause">{props.cause}</p>
            <button onClick={props.click}>Delete</button>
          </div>
        </>
  }
    </div>
    )
}

So what I expect is once I double click on a specific element for example 'The mountain' it will show me it's profile while the rest will show <h1>test</h1>.

Upvotes: 3

Views: 86

Answers (1)

Fyodor Yemelyanenko
Fyodor Yemelyanenko

Reputation: 11848

Most probably your doubleClickHandler is incorrect. As I understand you want to set formDouble to true for only single element, which you've clicked. In such case doubleClickHandler should be

doubleClickHandler = (index) => {
    this.setState({
        toKill: this.state.toKill.map((obj, objIndex) =>
            objIndex === index ? {...obj, formDouble: true} : {...obj, formDouble: false})
    })
}

A snippet using this code:

class App extends React.Component {
  state = {
    toKill: [
      { name: "Cersei Lannister", formDouble: false },
      { name: "Ser Ilyn Payne", formDouble: false },
      { name: "The Mountain", formDouble: false },
      { name: "The Hound", formDouble: false }
    ]
  };

  doubleClickHandler = index => {
    this.setState({
      toKill: this.state.toKill.map((obj, objIndex) =>
        objIndex === index
          ? { ...obj, formDouble: true }
          : { ...obj, formDouble: false }
      )
    });
  };

  render() {
    return (
      <div>
        {this.state.toKill.map((toKill, index) => {
          return (
            <ToKill
              double={() => this.doubleClickHandler(index)}
              formDouble={toKill.formDouble}
              click={() => this.deleteToKillHandler(index)}
              key={index + toKill.name}
              name={toKill.name}
              cause={toKill.cause}
              img={toKill.img}
            />
          );
        })}
      </div>
    );
  }
}

const ToKill = props => {
  return (
    <div className="hero-card" onDoubleClick={props.double}>
      {props.formDouble !== true ? (
        <h1>test</h1>
      ) : (
        <React.Fragment>
          <div className="hero-img-container">
            <img src={props.img} alt={props.name} className="hero-img" />
          </div>
          <div className="hero-desc">
            <h3 className="hero-name">{props.name}</h3>
            <p className="hero-cause">{props.cause}</p>
            <button onClick={props.click}>Delete</button>
          </div>
        </React.Fragment>
      )}
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Upvotes: 5

Related Questions