diff --git a/src/components/TodoApp/Todo.tsx b/src/components/TodoApp/Todo.tsx index 82a4bae..09f768e 100644 --- a/src/components/TodoApp/Todo.tsx +++ b/src/components/TodoApp/Todo.tsx @@ -1,8 +1,9 @@ -import { memo, useState } from "react"; +import { memo, useState, useEffect, useReducer } from "react"; import { tss } from "tss-react"; import { fr } from "@codegouvfr/react-dsfr"; import { Button } from "@codegouvfr/react-dsfr/Button"; import Checkbox from "@mui/material/Checkbox"; +import { useConstCallback } from "tools/useConstCallback"; export type Todo = { id: string; @@ -19,12 +20,33 @@ type TodoProps = { }; export const Todo = memo((props: TodoProps) => { - const { className, todo, onUpdateTodoText, onToggleTodo, onDeleteTodo } = props; + const { className, todo, onToggleTodo, onDeleteTodo } = props; - const [isEditing, setIsEditing] = useState(false); + // NOTE: Make sure it's not stale for when used in the reducer. + // We know it's constant because we also used useListCallbacks() in the parent component + // but this component is not supposed to be aware of that. + const onUpdateTodoText = useConstCallback(props.onUpdateTodoText); + + const [isEditing, setIsEditing] = useReducer((isEditing: boolean, isEditing_new: boolean) => { + if (isEditing_new === isEditing) { + return isEditing; + } + + if (!isEditing_new) { + onUpdateTodoText(text); + } + + return isEditing_new; + }, false); const { classes, cx } = useStyles({ isEditing }); + const [text, setText] = useState(todo.text); + + useEffect(() => { + setText(todo.text); + }, [todo.text]); + return (
onToggleTodo()} /> @@ -33,8 +55,8 @@ export const Todo = memo((props: TodoProps) => { {isEditing ? ( onUpdateTodoText(e.target.value)} + value={text} + onChange={e => setText(e.target.value)} onBlur={() => setIsEditing(false)} /> ) : ( @@ -44,7 +66,7 @@ export const Todo = memo((props: TodoProps) => {