Как передать функцию в state? Запоминается предыдущее значение
Всем привет!
Буду рад, если кто-то подскажет решение https://codesandbox.io/p/sandbox/function-in-state-does-not-work-8c9k5s
Сам пример - симуляция диалоговых окон с формами. То есть нажимаешь на одну кнопку - открывается одна форма с указанным onConfirm, на другую - другое действие.
Проблема в том, что renderComment запоминает comment на момент открытия этого самого окна и не изменяется при изменении инпута
Шаги:
- клик Open dialog 1
- ввожу в comment любое значение
- клик Confirm (comment пустой)
- клик Open dialog 2 (или 1, неважно)
- ввожу в comment другое значение
- клик Confirm - выводится значение, которое было после шага 4
const App = () => {
const [comment, setComment] = useState("");
const [func, setFunc] = useState(null);
const Buttons = () => {
const btns = [
{
title: "Open dialog 1",
onConfirm: renderComment("one"),
},
{
title: "Open dialog 2",
onConfirm: renderComment("two"),
},
];
return btns.map(({ title, onConfirm }) => (
<button key={title} onClick={() => setFunc(() => onConfirm)}>
{title}
</button>
));
};
const renderComment = (code) => () => {
alert(code + " - " + comment);
};
return (
<div>
<Buttons />
<br />
{func ? (
<>
<input
placeholder="comment"
onChange={(e) => setComment(e.target.value)}
/>
<p>Comment: {comment}</p>
<button onClick={func}>Confirm</button>
</>
) : null}
</div>
);
};
Ощущение, что я что-то базовое пропустил, но не пойму куда копать
Ответы (1 шт):
Упускаете такую вещь, как замыкание. Вы функцию кладете в стейт из функции, где comment "пуст" и при каждом изменении состояния(ввод в инпут), функция пересоздается, но то что отправлено в стейт помнит, где жила.
Измените код вот так:
Пусть renderComment
возвращает функцию, которая принимает текущие комментарии:
const renderComment = (code) => (comment) => {
alert(code + " - " + comment);
};
Ну и вызов фукнции будет выглядеть так:
<button onClick={() => func(comment)}>Confirm</button>
В целом, я бы рекомендовал не использовать такой подход, т.к. (ПРЕДПОЛОЖЕНИЕ) может быть утечка памяти из-за того, что ссылки на "старые" объекты хранятся. т.е. ссылка из старого компонента(перерисован уже много раз), и все что с ним было связано считается действующим и не будет удаляться сборщиком мусора.
P.S. Т.к. функция renderComment не имеет прямого отношения к текущему компоненту, ее можно вынести за его пределы