[SOLVED] How to apply styling to a specific item in an array

Issue

I’m trying to make a simple todo in react. I want to be able to click in the button next to the todo text and mark it as complete, with a line passing through it, so I guess the point of the button would be to toggle between the two stylings. But I don’t know how to apply the styling to that specific todo. Here’s my code so far:

import React, { useState } from 'react';

function App() {
  const [todos, setTodos] = useState([])

  const toggleComplete = (i) => {
    setTodos(todos.map((todo, k) => k === i ? {
      ...todo, complete: !todo.complete
    } : todo))
  }

  const handleSubmit = (event) => {
    event.preventDefault()
    const todo = event.target[0].value

    setTodos((prevTodos) => {
      return [...prevTodos, {
        userTodo: todo, completed: false, id: Math.random().toString()
      }]
    })
  }

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input placeholder='name'></input>
        <button type='submit'>submit</button>
      </form>

      <ul>
        {todos.map((todos) => <li key={todos.id}>

          <h4>{
          todos.completed ? <s><h4>{todos.userTodo}</h4></s> : <h4>{todos.userTodo}</h4>}
          </h4>

          <button onClick={toggleComplete}>Mark as complete</button>
          
        </li>)}
      </ul>
    </div>
  );
}

export default App;

Solution

You can see that the toggleComplete function takes a parameter i which is the id of the todo, so you should call it like onClick={() => toggleComplete(todos.id)}.

However this still didn’t work since you are assigning random numbers as strings as id to the todos then iterating on the array.

As Alex pointed out there the bug in your code regarding the completed toggle, so I fixed it and here’s a working version of the code you can take a look at and improve:

import React, { useState } from "react";

export default function App() {
  const [todos, setTodos] = useState([]);

  const toggleComplete = (i) => {
    setTodos(
      todos.map((todo, k) => {
        return k === i
          ? {
              ...todo,
              completed: !todo.completed
            }
          : todo;
      })
    );
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    const todo = event.target[0].value;

    setTodos((prevTodos) => {
      return [
        ...prevTodos,
        {
          userTodo: todo,
          completed: false,
          id: prevTodos.length
        }
      ];
    });
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input placeholder="name"></input>
        <button type="submit">submit</button>
      </form>

      <ul>
        {todos.map((todo) => (
          <li key={todo.id}>
            {todo.completed ? (
              <s>
                <p>{todo.userTodo}</p>
              </s>
            ) : (
              <p>{todo.userTodo}</p>
            )}

            <button onClick={() => toggleComplete(todo.id)}>
              Mark as complete
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Answered By – Bahax

Answer Checked By – Pedro (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.