Ivan Apungan
Ivan Apungan

Reputation: 534

React.js mapping how to change a single element

This is the code, so I have a component which renders a columns of intervals and I want to change the color of the table on click and drag but what happens is instead it changes everything... I'm a complete beginner, So I have really no idea how will I do that..

import React, { Component } from 'react';

class TableBody extends Component {
constructor(props) {
super(props);

this.state = {
  intervalItems: this.props.intervalItems,
  flag: 0,
  bgColor: '',
};
}

_mouseDown() {
this.setState(prevState => ({
  flag: 1,
}));
}

_mouseUp() {
this.setState(prevState => ({
  flag: 0,
}));
}

_mouseDrag(iD) {
if (this.state.flag == 1) {
  this.setState(prevState => ({
    bgColor: 'green',
  }));
} else {
  this.setState(prevState => ({
    bgColor: '',
  }));
}
}

render() {
const { dayItems, intervalItems } = this.props;

return (
  <tbody>
    {dayItems.map(v => (
      <tr key={v.id}>
        <th>
          <div>{v.day}</div>
        </th>

        {this.state.intervalItems.map((v, i) => (
          <td
            key={v.id}
            onMouseDown={() => this._mouseDown()}
            onMouseMove={() => this._mouseDrag()}
            onMouseUp={() => this._mouseUp()}
            className={`table-inside-default ${this.state.bgColor}`}
          >
            {v.interval}
          </td>
        ))}
      </tr>
    ))}
  </tbody>
);
}
}

export default TableBody;

Upvotes: 3

Views: 794

Answers (2)

Alberto
Alberto

Reputation: 1408

When you call _mouseUp(), _mouseDrag() or_ mouseDown() functions you change the color on the TableBody element and every single <td> item is getting the color from that property, so the color isn't individual to each <td>.

What I suggest you to do is create a child component with the <td> so the color and other properties you put in the child component will be individual to each child element. It would be something like this:

class TableBody extends Components {
  ...
  render() {
    return (
      <tbody>
      ...
      {this.state.intervalItems.map((v, i) => (
        <ItemTable item={v} />
      ))}
      </tbody>
    )
  }
}

class ItemTable extends Component {
  constructor(props) {
    super(props);
    this.state = {
      flag: 0,
      bgColor: '',
    };
  }
  _mouseDown() {
    this.setState(prevState => ({
      flag: 1,
    }));
  }

  _mouseUp() {
    this.setState(prevState => ({
      flag: 0,
    }));
  }

  _mouseDrag(iD) {
    if (this.state.flag == 1) {
      this.setState(prevState => ({
        bgColor: 'green',
      }));
    } else {
      this.setState(prevState => ({
        bgColor: '',
      }));
    }
  }
  render() {
    const { item } = this.props;
    return (
      <td
        key={item.id}
        onMouseDown={() => this._mouseDown()}
        onMouseMove={() => this._mouseDrag()}
        onMouseUp={() => this._mouseUp()}
        className={`table-inside-default ${this.state.bgColor}`}
      >
        {v.interval}
      </td>
    )
  }
}

Upvotes: 0

Lexis Hanson
Lexis Hanson

Reputation: 857

It looks like what's happening is that you're updating the color for all of your <td> tags at once. This is happening because they are all referencing the same piece of state, this.state.bgColor. When one td is changed, the component is re-rendered and all the elements pointing to this.state.bgColor will show up as the same color.

You might consider adding another property to your state, such as this.state.activeItem, and update it from your _mouseDrag function. Based on your activeItem, you can then set a designated color so that only that one is being updated. You might want to reset the activeItem in a separate function so that it gets cleared in between mouse events.

Upvotes: 4

Related Questions