0

const Component = ()=>{
const [list, setList] = useState(getLocalStorage());
const [isEditing, setIsEditing] = useState(false);
const [itemToEdit, setItemToEdit] = useState();
const refContainer = useRef(null);

const putLocalStorage = () => {
        localStorage.setItem("list", JSON.stringify(list));
    };

const editItem = (id) => {
        refContainer.current.focus();
        setItemToEdit(() => {
            return list.find((item) => item.id === id);
        });
        setIsEditing(true);
    };

const handleSubmit = (e)=>{
   e.preventDefault();
   let nameValue = refContainer.current.value;
   if (isEditing){
     setList(list.map((item)=>{
        if (item.id === itemToEdit.id){
             return {...item, name: nameValue};
        }
        else {
             return item;
        }
     );
   }
   else {
       let newItem = {
           id: new Date().getItem().toString(),
           name: nameValue,
       }
       setList([...list, newItem])
   }
   nameValue="";
   setIsEditing(false);
}


useEffect(() => {
        putLocalStorage();
    }, [list]);

return (
    <div>
         <form onSubmit={handleSubmit}>
             <input type="text" ref={refContainer} defaultValue={isEditing ? itemToEdit.name : ""}/>
             <button type="submit">submit</button>
        </form>
         <div>
                {list.map((item) => {
                    const { id, name } = item;
                    return (
                        <div>
                            <h2>{name}</h2>
                            <button onClick={() => editItem(id)}>edit</button>
                            <button onClick={() => deleteItem(id)}>
                                delete
                            </button>
                        </div>
                    );
                })}
            </div>
    </div>
)
}



So this part:

<input type="text" ref={refContainer} defaultValue={isEditing ? itemToEdit.name : ""} />

I want to show to users what they are editing by displaying the itemToEdit on the input.

It works on the first time when the user clicks edit button But after that, the defaultValue does not change to itemToEdit

Do you guys have any idea for the solution? (i could use controlled input instead, but i want to try it with useRef only)

Otherwise, placeholder will be the only solution...

  • Why do you prefer `defaultValue` over `value`? When you want a sideeffect on your form inputs, you use `value` and its source is the `state`. `defaultValue` is not the right tool. Read the first para in the [doc](https://reactjs.org/docs/uncontrolled-components.html) ```In most cases, we recommend using controlled components to implement forms. In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself.``` – Arup Rakshit Jul 14 '22 at 14:36
  • because with useRef you cannot change value once set? and also i dont wish to trigger whole re-render each time i change input value. isnt useRef better in performance in this sense? – jaehyuk kim Jul 14 '22 at 14:39
  • I will say use state and value. `defaultValue` is not for this usecase. It mostly used in a one and off compoents.. For e.g. a contact form in public website to write to the site owner something.. For this an HTML and its own solution is enough. We need no react state for this. You still can use state, but not needed. – Arup Rakshit Jul 14 '22 at 14:44

1 Answers1

1

The defaultValue property only works for inicial rendering, that is the reason that your desired behavior works one time and then stops. See a similar question here: React input defaultValue doesn't update with state

One possible solution still using refs is to set the itemToEdit name directly into the input value using ref.current.value.

const editItem = (id) => {
        refContainer.current.focus();
        setItemToEdit(() => {
            const item = list.find((item) => item.id === id);
            refContainer.current.value = item.name;
            return item;
        });
        setIsEditing(true);
    };
Ary Barros
  • 307
  • 2
  • 10