3

I am trying to create a simple to do page using react after adding to do list item i am attaching trash icon & when user click its required its corresponding list item is deleted , i want to know if it can be done without using id, for ex in jquery it was simple (this.remove )

 const [input, setValue] = useState("");
  const [todos, setTodos] = useState([]);
  // passing  entered
  const handleInput = (event) => {
    setValue(event.target.value);
  };

  const lp = (event) => {
    // let c = [1,2,34,55]

    event.preventDefault();
    // if no input nothing will happen return none
    if (!input) return;
    // using spread operator its used whenever we need to add array data to exiting array
    const newTodos = [...todos, input];

    setTodos(newTodos);
    // clearing input text
    setValue("");
  };
  const handeldel=(e) => {
//  how to delete
  
  }

  return (
    <div>
      <div class="input-group mb-3">
        <input
          className="form-control border-primary font-weight-bold"
          style={{ height: 60 }}
          placeholder="Enter Text here"
          type="text"
          value={input}
          onChange={handleInput}
        />
        <div class="input-group-append">
          <button
            className="input-group-append font-weight-bolder "
            style={{ fontSize: 20 }}
            onClick={lp}
          >
            {" "}
            <i class="fas fa-plus-square fa-2x p-2"></i>{" "}
          </button>
        </div>
      </div>

      {todos.map((x) => (
        <ol style={{ listStyle: "none" }}>
          <li className="font-weight-bolder table-bordered" style={{fontSize:20}}>
            {x} <i class="fas fa-trash-alt" onClick={handeldel}></i>
          </li>
        </ol>
      ))}
    </div>
  );
};

3 Answers3

1

You can use an index in order to delete the specific item from the list.

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

And then HTML

 {todos.map((x, index) => (
     <ol style={{ listStyle: "none" }}>
        <li className="font-weight-bolder table-bordered" style={{fontSize:20}}>
           {x} <i class="fas fa-trash-alt" onClick={() => handeldel(index)}></i>
        </li>
      </ol>
  ))}
Surjeet Bhadauriya
  • 6,755
  • 3
  • 34
  • 52
  • In your implementation, you’d still need some sort of identifiable value. As you progress through your React skills, you’ll see the need for an identifier will become more and more prevalent, so I would avoid trying to have a sort of ‘self-destructable’ component in your todo list. However, if you must know, you may implement this feature by creating a separate component for your todo items and run a built in method in the Child props object called unmountMe() : https://stackoverflow.com/questions/36985738/how-to-unmount-unrender-or-remove-a-component-from-itself-in-a-react-redux-typ – Shah Mar 26 '21 at 06:26
  • The error message you provided here doesn't seem to be relatable with the code. Can you please check by putting console.log in handeldel function and check what's happening there? – Surjeet Bhadauriya Mar 26 '21 at 06:37
  • 1
    thanks surjeet it worked just one doubt why handeldel is called inside arrow function of onclick though i have already declared it cant i use it directly ? –  Mar 26 '21 at 06:37
  • 1
    Yes because if you call it like handeldel(index) then it will be called in an infinite loop. However, you can call it directly if don't pass any argument like you were doing before. But if are passing the arguments then it becomes a function call. So we have to make a callback to avoid the infinite loop calls. This way we are just binding the function not calling it. – Surjeet Bhadauriya Mar 26 '21 at 06:41
1
 const handeldel=(index) => {
  todos.splice(index, 1);
  }

todos.map((x, index) => (...
...
<i class="fas fa-trash-alt" onClick={(e)=>handeldel(index)}></i>
WebEXP0528
  • 561
  • 3
  • 9
0

As far as you're mapping an array to make a todos list there're a couple things you need to have in mind

When mapping arrays your node should have an unique key as default prop

// GOOD!!!
{todos.map(todo => (
  <ol key={todo.uniqueKey} {...rest}>
    ...
  </ol>
))}

You shouldn't pass index as your node key

// Don't do this, BAD!!!
{todos.map((todo, index) => (
  <ol key={index} {...rest}>
    ...
  </ol>
))}

Now, answering to your question, there's a simple way to do this, so i'll share with you the one i think is the best:

// Imagine you have these
const [todos, setTodos] = useState([
 { key: 'item1', content: 'some content' },
 { key: 'item2', content: 'some content' },
 { key: 'item3', content: 'some content' },
 { key: 'item4', content: 'some content' }
]);

// filter return a new array where the id is not like the one passed to handle del
// this is a function that returns a function
const handleDel = todoKey => e => setTodos(prev => prev.filter(todo => todo.key !== todoKey));

// Passing to the map you'll have something like
{todos.map(todo => (
  <ol key={todo.key} style={{ listStyle: "none" }}>
    <li className="font-weight-bolder table-bordered" style={{fontSize:20}}>
      {todo.content} <i class="fas fa-trash-alt" onClick={handleDel(todo.key)}></i>
    </li>
  </ol>
))}

If using above approach then you have to modify your lp and handleInput functions, i'm giving you a simple example

// Here you're setting the unique key with Date.now()
// You're assigning an object to store what you need and save it later
// in your todos list
const handleInput = e => setValue({ key: new Date.now(), content: e.target.value });

const lp = (event) => {
  event.preventDefault(); // as soon as it's not a submit button you don't need to preventDefault 
  if (!input) return;
  // You can access to your previous state from inside your setState
  // function, that's the same as you were doing but less verbose
  setTodos(prevTodos => ([...prevTodos, input]));
  // clearing input text
  setValue({ key: null, content: '' });
};

// In your input you'll need to change to this as far as you're setting state with an object

<input
  className="form-control border-primary font-weight-bold"
  style={{ height: 60 }}
  placeholder="Enter Text here"
  type="text"
  value={input.content} // <-- this is what you need to change
  onChange={handleInput}
/>

// to not have problems with useState always initialize it with what you
// will need, in this example your input state will change to this

const [input, setValue] = useState({
  key: null,
  content: ''
});

I hope this helps you to understand more about react and how it works (also to teach some good techniques in case you didn't know 'em)