-1

I have a list of todo items where I have to show the details of todo item on click of a button. I have two buttons "View Details" and "Hide Details" for the same.Below is code:

class Todos extends React.Component{
    constructor(props){
        super(props);
        this.state={
          shown:false,
          todos: []
        }
    }
showDetails = (bool) => {
      this.setState({
       shown:bool
      });
    }

render(){
     const { shown, todos } = this.state;
        return(
        <div>
            <ul>
              {todos.map((todo,i)=>(
                <li key={todo.id}>
                  <span >{todo.title}</span>
                 <button onClick={this.showDetails.bind(this, true)}>View Details</button>
                 <button onClick={this.showDetails.bind(this, false)}>Hide Details</button>

                  {shown && (<div>
                    Description:{todo.description}<br/>
                    Due Date: {todo.status} <br/>
                  </div>)  }               
                </li>
              
              ))}
            </ul>
}
           

The issue here is that I will be having multiple view and hide buttons for each todo item and whenever I click on that button, details of all the todo items gets displayed. How can I click a todo item and able to see only that todo item's detailed view?

3
  • why are passing null instead of this? Commented Apr 7, 2021 at 2:53
  • i see you edited, is it working now? Commented Apr 7, 2021 at 3:00
  • Hey, Edited the code, but still the issue persists.How do I associate "shown" value with a single todo item ? Commented Apr 7, 2021 at 3:00

2 Answers 2

3

The easiest and most recommended way would be to break down each Todo into a seperate component rather than just mapping JSX for each.

const Todo = ({ todo }) => {
  const [visible, setVisbile] = useState(true)

  const toggleDetails = () => {
    setVisbile(!visible)
  }

  return (
    <li key={todo.id}>
      <span >{todo.title}</span>
      <button onClick={toggleDetails}>{ visible ? 'Hide Details' : 'View Details' }</button>
      {visible && (<div>
        Description:{todo.description}<br/>
        Due Date: {todo.status} <br/>
      </div>)  }               
    </li>
  )
}
export default Todo;

if you don't want to use Hooks and wish to use the class based version

class Todo extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      visible: true
    }
  }

  toggleDetails = () => {
    const newToggleState = !this.state.visible
    this.setState({ visible: newToggleState })
  }

  render () {
    const { todo } = this.props
    const { visible } = this.state
    return (
      <li key={todo.id}>
        <span >{todo.title}</span>
        <button onClick={this.toggleDetails}>{ visible ? 'Hide Details' : 'View Details' }</button>
        {visible && (<div>
          Description:{todo.description}<br/>
          Due Date: {todo.status} <br/>
        </div>)  }               
      </li>
    )
  }
}

you can import this in your current component like this

render(){
   const { shown, todos } = this.state;
      return(
      <div>
          <ul>
            {todos.map((todo,i)=>(
              <Todo key={todo.id} todo={todo}/>
            ))}
          </ul>
      </div>
      )
  }
}
  
4
  • Hey, Thanks for your time! Can you please suggest an approach which does not use hooks ? Commented Apr 7, 2021 at 3:35
  • However I suggest you to start using hooks if you have just started learning react as the community has shifted to using hooks as primary format Commented Apr 7, 2021 at 3:59
  • Okay, thank you so much !! I recently started learning react and will be learning hooks too in a few days. Commented Apr 7, 2021 at 4:00
  • If this answer works, please mark it as an accepted answer, it helps us get motivated and help as many people we can. Thanks :) Commented Apr 7, 2021 at 4:02
0
 class Todos extends React.Component{
constructor(props){
    super(props);
    this.state={
      shown:false,
      selectedId:'',
      todos: []
    }
}
showDetails = (bool,id) => {
  this.setState({
   shown:bool,
   selectedId:id
  });
}

render(){
 const { shown, todos,selectedId } = this.state;
    return(
    <div>
        <ul>
          {todos.map((todo,i)=>(
            <li key={todo.id}>
              <span >{todo.title}</span>
             <button onClick={this.showDetails.bind(this, true,todo.id)}>View Details</button>
             <button onClick={this.showDetails.bind(this, false,todo.id)}>Hide Details</button>

              {shown &&selectedId===todo.id (<div>
                Description:{todo.description}<br/>
                Due Date: {todo.status} <br/>
              </div>)  }               
            </li>
          
          ))}
        </ul>

}

The method mentioned in the code has the todo id passed into the function . So that the particcular Todo to be viewed or hidden shall be controlled

2
  • Hey, Thanks for your time! This works. However, I have multiple todo items and also multiple view and Hide details buttons. If I am clicking view Details for one todo item and hide details of another todo item then also it's working which should not happen ideally. Can you please advice on this ? Commented Apr 7, 2021 at 3:25
  • No, actually there are multiple todo items. Each todo item has view and hide details button. Ideally,when we click on view details button of one todo item then the hide button of that todo item only should be able to hide it.However, According to the code you have written , if I click on view details button of one todo item and hide details of another todo item then also the details are getting hidden. Commented Apr 7, 2021 at 3:56

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.