Home > Net >  conditional Styles in react
conditional Styles in react

Time:11-03

I am making a todo list and in the following Tasks component i have an li component with mapped data i want to conditionally add a strikethrough on the task for which i used a useState hook with intial property as null. I then added onClick functions to change state to true and false respectively but my style is not being applied :( Below is the code for the same

`import React, {useState} from 'react';
import "./Tasks.css";
import DoneIcon from '@mui/icons-material/Done';
import CloseIcon from '@mui/icons-material/Close';

function Tasks(props) {

  const [done, setDone] = useState(null);

  return (
    <div className="tasks">
        {props.items.map(item => (
          <li key={item.id} onClick={() => setDone(false)} style={{textDecorationLine: done && 'line-through'}}>{item.text} 
          <div>
          <button onClick={() => setDone(true)} style={{color: "green"}}><DoneIcon/></button>
          <button style={{color: "red"}}><CloseIcon/></button>
          </div>
      </li>
        ))}
        
    </div>
  )
}

export default Tasks;`

I am making a todo list and in the following Tasks component i have an li component with mapped data i want to conditionally add a strikethrough on the task for which i used a useState hook with intial property as null. I then added onClick functions to change state to true and false respectively but my style is not being applied :( Here is the code for the same

CodePudding user response:

Your code has a couple of issues:

  1. If you want to save the state for each task, you can't use a single boolean. You need and array or object that holds one value per task.
  2. When you click your Done button, both onClick callbacks are triggered (the one for <button> and the one for <li>), setting the value of done to true and immediately to false again.

To solve [1], you can make your done variable an object, where each key is an item id and matching value is a boolean that determines if the task is done.

To solve [2], remove onClick from the <li>. You can still achieve a toggle effect if you set the task state based on previous state, in the button's onClick.

The following code should be what you need:

  // done is an object that maps task ids to booleans
  const [done, setDone] = useState({});

  return (
    <div className="tasks">
      {props.items.map(item => (
        <li key={item.id} style={{textDecorationLine: done[item.id] && 'line-through'}}>{item.text} 
          <div>
            <button onClick={() => setDone(prevState => ({...prevState, [item.id]: !prevState[item.id]}))} style={{color: "green"}}><DoneIcon/></button>
            <button style={{color: "red"}}><CloseIcon/></button>
          </div>
        </li>
      ))}
    </div>
  )

CodePudding user response:

You need to save the item.id to determine which item was clicked, not a boolean.

import React, {useState} from 'react';
import "./Tasks.css";
import DoneIcon from '@mui/icons-material/Done';
import CloseIcon from '@mui/icons-material/Close';

function Tasks(props) {

  const [taskWasDone, setTaskWasDone] = useState(null);

  return (
    <div className="tasks">
        {props.items.map(item => (
          <li key={item.id} onClick={() => setTaskWasDone(null)} style={{textDecorationLine: taskWasDone === item.id && 'line-through'}}>{item.text} 
          <div>
            <button onClick={() => setTaskWasDone(item.id)} style={{color: "green"}}><DoneIcon/></button>
            <button style={{color: "red"}}><CloseIcon/></button>
          </div>
      </li>
        ))}
        
    </div>
  )
}

export default Tasks;
  • Related