0

I have a list of board numbers. This list I am exporting and mapping into it to create the elements how I want. Now, I need each of these elements to have its own count, and when I click on one of them, I need to append symbol to the clicked element

The problem is that onClick event is updating all of my elemtents.

Here is a live demo, and also below is my current code:

export class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: ''
    }
  }
  
  appendChild(id) {
    console.log(id) // I am successfuly getting the id of the clicked element

    // This code should update only the id that I have clicked
    this.setState(prevState => {
      return {
        count: prevState.count + '◘'
      }
    });
  }

  render() {
    const boardItems = BoardNumbers.map((item) => 
      <div key={item.id} className={(item.color === "black") ? 'black-item' : 'red-item'}>
        <div onClick={this.appendChild.bind(this, item.id)} className="value">{item.id}
          {this.state.count}
        </div>
      </div>
    );

    return (
      <>
        {boardItems}
      </>
    )
  }
}
Alex
  • 133
  • 2
  • 10

2 Answers2

3

You need to save all items in your state so that you can update the specific item's count. I have also added the comments, Demo

import React from 'react';
import { BoardNumbers } from './BoardNumbers';
import './App.css';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      items: BoardNumbers, // all board items 
      currentItem: {count: ''}

    }
  }

//this function is used to update count and for setting current clicked item
  updateItem =(item)=>{
    const updatedItem ={...item, count: item.count ? item.count + '◘' :'◘' }
    this.setState({currentItem: updatedItem})
    console.log(updatedItem)
    return updatedItem;
  }
  
  appendChild(id) {
    console.log(id)
  //filter the required item to update its count
    const items = this.state.items.map((item)=> item.id===id ? this.updateItem(item) : item);
    
    this.setState({items}) //set state with new items
  }

  render() {
    const boardItems = this.state.items.map((item) => 
      <div key={item.id} className={(item.color === "black") ? 'black-item' : 'red-item'}>
        <div onClick={this.appendChild.bind(this, item.id)} className="value">{item.id}
        {item.count && item.count}
        </div>
      </div>
    );

    return (
      <>
        <div className="mainWrapper">
            <div className="container-first">
            <div className="zero-item">
              <div className="value">0</div>
            </div>

            {boardItems}

            <div className="column-item">
              <div className="value">2-1</div>
            </div>
            <div className="column-item">
              <div className="value">2-1</div>
            </div>
            <div className="column-item">
              <div className="value">2-1</div>
            </div>
          </div>

          <div className="container-second">
            <div className="doz-item">
              <div>1st 12</div>
            </div>
            <div className="doz-item">
              <div>2nd 12</div>
            </div>
            <div className="doz-item">
              <div>3rd 12</div>
            </div>
          </div>
          
          <div className="container-third">
            <div className="outside-section">
              <div>1-18</div>
            </div>
            <div className="outside-section">
              <div>EVEN</div>
            </div>
            <div className="outside-section">
              <div><div className="rhomb-red"></div></div>
            </div>
            <div className="outside-section">
              <div><div className="rhomb-black"></div></div>
            </div>
            <div className="outside-section">
              <div>ODD</div>
            </div>
            <div className="outside-section">
              <div>19-36</div>
            </div>
          </div>
        </div>
      </>
    );
  }
}

export default App;
bakar_dev
  • 936
  • 4
  • 13
  • 1
    @baker_dev This is exactly what I wanted except for the previously clicked item that the state resets. What do I need to change to the current code in order to click multiple items? – Alex Aug 20 '20 at 12:17
  • 1
    Then you just need to map through the `this.state.items` not `BoardNumbers` and just show the `count` , check this i have updated: https://stackblitz.com/edit/react-tzpugd?file=src%2FApp.js – bakar_dev Aug 20 '20 at 12:21
1

You have only one count state. You need one count state for each number.

In your example the behaviour is: When you click on an element you add the symbol to your single state variable. When you click on another element, you add additional symbol to the same single state variable. And for each number you print the same single state variable. That's why in each field the number of symbols is the same.

  • Press item.id 4 -> count = 1x Symbol
  • Press item.id 7 -> count = 2x Symbols
  • Press item.id 9 -> count = 3x Symbols

And then you display all the different item.ids with the same count state variable.

Amel
  • 653
  • 9
  • 15
  • So I need a different state for all of my elements? How can I update the state for the clicked element given that the state names have to be different? – Alex Aug 20 '20 at 12:03
  • 1
    You could replace the state `count` with an Object `countObj` that contains all numbers and a Boolean value for each number. OnClick Event you modify the Object and then pass it with `setState`, the whole Object. You basically replace the whole old Object with the new modified Object. That way you also would not need the `BoardNumber.js`. Another fancy attempt could be to `setState` with dynamic keys: [here](https://stackoverflow.com/questions/29280445/reactjs-setstate-with-a-dynamic-key-name). – Amel Aug 20 '20 at 12:22