Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJS hover/mouseover effect for one list item instead of all list items

I am a React novice, so this might seem really simple, or maybe it isn't, I'm not sure. I'm building a basic to-do list. I want a mouseover effect on list items to pop up "delete this" text. But for my code so far, when I mouseover a list item, "delete this" pops up for all list items instead of just the one.

When I tried solving this by creating a new component for individual list items, that didn't seem to work. Any help is much appreciated!

class ToDosContainer extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      heading: 'Something You Need To Do?',
      todos: [
        'wake up',
        'brush your teeth'
      ],
    }

    this.addToDo = this.addToDo.bind(this)
  }

  addToDo(todo) {
    this.setState((state) => ({
      todos: state.todos.concat([todo])
    }))
  }
  render() {
    return (
      <div>
        <h1>To Do List</h1>
        <h3>{this.state.heading}</h3>
        <AddToDo addNew={this.addToDo} />
        <ShowList tasks={this.state.todos} />
      </div>  
    )
  }
}

class AddToDo extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      newToDo: ''
    }

    this.updateNewToDo = this.updateNewToDo.bind(this)
    this.handleAddToDo = this.handleAddToDo.bind(this)

  }

  //I think I can delete this part
  updateNewToDo(e) {
    this.setState({
      newToDo: e.target.value
    })
  }
 //

  handleAddToDo() {
    this.props.addNew(this.state.newToDo)
    this.setState({
      newToDo: ''
    })
  }

  render() {
    return (
      <div>
        <input
          type="text"
          value={this.state.newToDo}
          onChange={this.updateNewToDo}
         />
        <button onClick={this.handleAddToDo}> Add To Do </button>
      </div>
    )
  }
}

class ShowList extends React.Component {

  constructor(props) {
    super(props)

    this.state = {
      newToDo: ''
    }
  }

  onMouseOver(e) { 
    this.setState({
      text: 'delete me'
    })
    console.log('hey')
  }

  onMouseOut(e) { 
     this.setState({
      text: ''
    })
     console.log('hey hey')

  }

  render() {
   const { text } = this.state;
   return (
    <div>
       <h4>To Do's</h4>
       <ul>
          {this.props.tasks.map((todo) => {
            return <li onMouseEnter={this.onMouseOver.bind(this)} onMouseLeave={this.onMouseOut.bind(this)}> {todo} {text}</li>
          })}
       </ul>
    </div>
   ) 
  }
}

ReactDOM.render(<ToDosContainer />, document.getElementById('helloworld')); 
like image 761
bfoley_teamug Avatar asked May 31 '18 22:05

bfoley_teamug


1 Answers

I would make a Task component. You don't want to set the state of the text in the ListView component, because then this.state.text is shared by each task in the map. Each task should be aware of its own hover, and not the hover of the other children.

class Task extends React.Component {
  state = {
    text: ""
  };
  onMouseOver(e) {
    this.setState({
      text: "delete me"
    });
  }

  onMouseOut(e) {
    this.setState({
      text: ""
    });
  }

  render() {
    return (
      <li
        onMouseEnter={this.onMouseOver.bind(this)}
        onMouseLeave={this.onMouseOut.bind(this)}
      >
        {this.props.todo} {this.state.text}
      </li>
    );
  }
}


class ShowList extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      newToDo: ""
    };
  }

  render() {
    const { text } = this.state;
    return (
      <div>
        <h4>To Do's</h4>
        <ul>
          {this.props.tasks.map(todo => {
            return <Task todo={todo} />;
          })}
        </ul>
      </div>
    );
  }
}
like image 143
Trevor Avatar answered Nov 14 '22 10:11

Trevor