0

I would like the button to change the current filteredTodo's property "filter" from true to false when clicked, but i'm having problems targeting said object and its property.

import React, {useState} from 'react';

const Todo = props => {

    const [todos, setTodos] = useState([]);
    const onSubmit = e =>{
        e.preventDefault();
        setTodos([
            ...todos, {
                name :e.target.name.value,
                filter :e.target.filter.value,
            }
        ])
        e.target.name.value = "";
        console.log(todos);
    }
    const onClick = e => {

    }
    return (
        <div>
            <div>
                <form onSubmit={onSubmit}>
                    <input type="text" placeholder="Get MERN black belt" name="name"/>
                    <input type="hidden" name="filter" value="true"/>
                    <button type="submit">Add</button>
                </form>
            </div>
            {todos.filter(todo=>todo.filter.includes("true")).map((filteredTodo,i) =>(
                <div key={i}>
                    <label>{filteredTodo.name}</label>
                    <input type="checkbox"/>
                    <button onClick={onClick} name="filter" type="submit">Delete</button>
                </div>
            ))}
        </div>
    );
}
export default Todo;

2 Answers2

0

Instead of filtering and mapping, you can simply map and return the element based on filter condition. That way you can rely on the index property obtained from map to update the todo on click since you do not have any unique id associated with todos

const Todo = props => {

    const [todos, setTodos] = useState([]);
    const onSubmit = e =>{
        e.preventDefault();
        setTodos([
            ...todos, {
                name :e.target.name.value,
                filter :e.target.filter.value,
            }
        ])
        e.target.name.value = "";
        console.log(todos);
    }
    const onClick = index => {
       setTodos(prev => [...prev.slice(0, index), {...prev[index], filter: false}, ...prev.slice(index + 1)]);
    }
    return (
        <div>
            <div>
                <form onSubmit={onSubmit}>
                    <input type="text" placeholder="Get MERN black belt" name="name"/>
                    <input type="hidden" name="filter" value="true"/>
                    <button type="submit">Add</button>
                </form>
            </div>
            {todos.map((filteredTodo,index) =>{
             if(odo.filter.includes("true")) {
               return (<div key={i}>
                    <label>{filteredTodo.name}</label>
                    <input type="checkbox"/>
                    <button onClick={() => onClick(index)} name="filter" type="submit">Delete</button>
                </div>
               )
             }
             return null; // returning null will not render anything
            })}
        </div>
    );
}
export default Todo;

However I would recommend you to generator a unique id when you create a todo so that you can uniquely identify todos. Also it will help you in rendering optimization by providing the unique id as key to returned div element from map

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
-1

Solved it! Credits to How do I update states onchange in an array of object in React Hooks

import React, {useState} from 'react';

const Todo = props => {

    const [todos, setTodos] = useState([]);
    const onSubmit = e =>{
        e.preventDefault();
        setTodos([
            ...todos, {
                name :e.target.name.value,
                filter :e.target.filter.value,
            }
        ])
        e.target.name.value = "";
        console.log(todos);
    }
    const onClick = i => e => {
        let newArr = [...todos];
        newArr[i].filter = "false";
        setTodos(newArr);
    }
    return (
        <div>
            <div>
                <form onSubmit={onSubmit}>
                    <input type="text" placeholder="Get MERN black belt" name="name"/>
                    <input type="hidden" name="filter" value="true"/>
                    <button type="submit">Add</button>
                </form>
            </div>
            {todos.filter(todo=>todo.filter.includes("true")).map((filteredTodo,i) =>(
                <div key={i}>
                    <label>{filteredTodo.name}</label>
                    <input type="checkbox"/>
                    <button onClick={onClick(i)} type="submit">Delete</button>
                </div>
            ))}
        </div>
    );
}
export default Todo;
  • Great, this will only work if the todos in your array are all having filtered state as true. If any todo in the center has filtered state false this will fail – Shubham Khatri May 14 '20 at 18:09
  • Could you elaborate? i set a hidden input thus every todo should be set as true, and once deleted would be set as false but still stored in the array. Am i missing something here? – Bobbie Dinh May 14 '20 at 18:15
  • If you set filtered to false for a todo, now next time you try to set filtered to false, you will be updating a wrong todo with your code. You can try it out. Please check my answer for more details – Shubham Khatri May 14 '20 at 18:19