3

I'm trying to use setState in map function what I want to make when I hit click button that makes states changed

I searched "In map function changed setState" in stackoverflow

but It was hard to understand..and apply my case

this.state = {
      categories: [
        {
          category: 'sports',
          ariticles: [],
          isClick: true
        },

...
...

 return (
      <div>
        <hr></hr>

        <div className="categoryBtn">
          {this.state.map(item => (
            <button
              onClick={
                () => this.setState(() => (item.isClick = false))
                // () => console.log((item.isClick = false))
                // this.setState(() => (item.isClick = !item.isClick))
              }
            >
              {' '}
              {item.category}
            </button>
          ))}

when I hit my button I got error ' this.state.map is not a function'

I expect when I hit button, isClick will be toggle

young ban
  • 169
  • 1
  • 12
  • .map is only available in an iterable, your `this.state` is an object, i think you need to refer `categories` array. so it should be `this.state.categories.map(...` – Anuja Sep 08 '19 at 03:57

2 Answers2

4

Your this.state refers to an object containing an array,

categories: [...]

So you'd need to map over this.state.categories.map instead of this.state.map


And also, I've noticed that button event handler mutates the state.

<button onClick={() => this.setState(() => (item.isClick = false))}>
  {item.category}
</button>

You'd need to return a new item reference to notify react that the state has been changed as well as adding a key prop.

Thankfully, someone asked a question about the reason for using key (only 2 hours ago) and replied, which you can refer to.

https://stackoverflow.com/a/57838612/4035

<button key={item.category} onClick={() => this.setState({
    find the item by searching for each item in `this.state.cateogies`
  })}>
  {item.category}
</button>;

But then it gets tough to find the right element, so I'd recommend to normalize(meaning change the this.state.categories) too look like following for easier way to set the state.

// From this
this.state = {
  categories: [
    {
      category: "sports",
      ariticles: [],
      isClick: true
    },
    {
      category: "sports",
      ariticles: [],
      isClick: true
    }
  ]
};

// to this
this.state = {
  categories: {
    sports: {
      category: 'sports',
      ariticles: [],
      isClick: true
    },
    news: {
      category: 'news',
      ariticles: [],
      isClick: true
    }
  }
};

This way, you can set the state like following.

<button
  key={item.category}
  onClick={() =>
    this.setState({
      [item.category]: {
        isClick: false
      }
    })
  }
>
  {item.category}
</button>

Reply to the comment below (I've translated the comment for non-Korean speakers)

So you can't use .map any more after making such a change?

I am sorry, I should've updated the category item generation code after the state update.

No, you can't use .map as it's now an object. But thankfully, you can use either Object.keys/value/entries to iterate the this.state.categories.

You can click on "Run code snippet" button to see the output

let state = {
  categories: {
    sports: {
      category: "sports",
      ariticles: [],
      isClick: true
    },
    news: {
      category: "news",
      ariticles: [],
      isClick: true
    }
  }
};

Object.entries(state.categories).map(([id, item]) => console.log(item))

So your code would look like something like,

<div className="categoryBtn">
  {Object.entries(state.categories).map(([id, item]) => (
    <button
      key={id}
      onClick={() =>
        this.setState({
          [item.category]: {
            isClick: false
          }
        })
      }
    >
      {item.category}
    </button>
  ))}
</div>
dance2die
  • 35,807
  • 39
  • 131
  • 194
2

Try this :::

{this.state.categories.map(item => ( ..... ))}
Mariselvam
  • 149
  • 4
  • 2
    Nothing new compared to the already existing answer. No effort to provide some explaination why the code did not work and this one should. – Pinke Helga Sep 08 '19 at 03:53
  • I believe I typed a bit faster than he did. But as @Mariselvam is a new contributor, thank you for replying to the answer. You could try to provide more thorought answer next time and here is my +1 for {...} – dance2die Sep 08 '19 at 04:03