Home > Software engineering >  How to move a Todo element at the end of the list and bring it back to the same position when undone
How to move a Todo element at the end of the list and bring it back to the same position when undone

Time:11-06

I'm learning React for only a few days now. I'm making a Todo app and I would like to add the following feature: when I mark a task as done, it should move to bottom. If I make the same task as undone then it should maintain its original position.

My code starting from the App structure:

import './App.css';
import Header from './components/Header';
import List from './components/List';

function App() {
  return (
    <div className="Todo App">
      <Header />
      <List />
    </div>
  );
}

export default App;
const Header = () => {
    return (
        <h1>My Todo App</h1>
    );
};

export default Header;
import Item from './Item';
import './AllComponents.css'

function List({ }) {

  const [value, setValue] = useState("");
  const [todos, setTodos] = useState([]);

  const handleSubmit = e => {
    e.preventDefault();
    if (!value) return;
    addTodo(value);
    setValue("");
  };

  const addTodo = text => {
    const newTodos = [...todos, { text }];
    setTodos(newTodos);
  };

  const markTodo = index => {
    const newTodos = [...todos];
    newTodos[index].isDone = !newTodos[index].isDone;
    setTodos(newTodos);
  };

  const removeTodo = index => {
    const newTodos = [...todos];
    newTodos.splice(index, 1);
    setTodos(newTodos);
  };

  return (
      <div className="container">
        <form onSubmit={handleSubmit}>
          <input 
          type="text" 
          value={value}
          placeholder="Add an item"
          onChange={e => setValue(e.target.value)} />
          <button type="submit">Add</button>
        </form>
        <li className="li-items">
          {todos.map((todo, index) => (
              <Item
                key={index}
                index={index}
                todo={todo}
                markTodo={markTodo}
                removeTodo={removeTodo}
              />
          ))}
        </li>
      </div>
  )
};

export default List;
import React from "react";


const Item = ({ todo, index, markTodo, removeTodo }) => {

  return (
    <div className="full-element">
        <span className="todo-item" style={{ textDecoration: todo.isDone ? "line-through" : "" }}>{todo.text}</span>
        <div className="buttons">
          <button onClick={() => markTodo(index)}>✓</button>{' '}
          <button onClick={() => removeTodo(index)}>✕</button>{' '}
        </div>  
    </div>
  )
};

export default Item;

My App looks like this now:

enter image description here

Can someone with more experience please take a look and point me in the right direction? Thank you

CodePudding user response:

Display two lists, one not done and one done, one after another

{todos.filter(todo => !todo.isDone).map((todo, index) => (
  <Item
    key={index}
    index={index}
    todo={todo}
    markTodo={markTodo}
    removeTodo={removeTodo}
  />
))}
{todos.filter(todo => todo.isDone).map((todo, index) => (
  <Item
    key={index}
    index={index}
    todo={todo}
    markTodo={markTodo}
    removeTodo={removeTodo}
  />
))}

P.S.

<li> is list item, not list, you should use <ul> and each item should be <li>

P.S. 2

index isn't a good key

  • Related