Comments 9
Ваши примеры с useRef ошибочны: они могут обработать событие для более нового значения value чем было отображено, а могут и не обработать.
Представьте, что где-то в дочернем компоненте есть вот такой код:
onChangeFirstName(...);
onChangeLastName(...);
В таком случае значение, переданное в onChange, будет зависеть от того, успеет ли React выполнить рендер между этими двумя вызовами. Что, к слову, зависит от того, выполняется ли код выше в обработчике события...
А ещё с Concurrent Mode в ваш valueCopy может попасть value, который вообще никогда не попадал в DOM (например, из-за Suspense).
Вы правы, последовательное выполнение функций работать не будет, благо контекст задачи не предполагает последовательных вызовов. А как вы решаете данную проблему, не мемоизируете?
Решение ведь элементарное. Просто нужно использовать MobX.
class ComponentLocalState {
counter = 0;
firstName = '';
lastName = '';
constructor() {
makeAutoObservable(this);
}
incr = () => {
this.counter++;
}
decr = () => {
this.counter--;
}
handleFirstNameChange = (e: ChangeEvent<HTMLInputElement>) => {
this.firstName = e.target.value;
}
handleLastNameChange = (e: ChangeEvent<HTMLInputElement>) => {
this.lastName = e.target.value;
}
}
export const MyComponent = observer((props: IMyComponentProps) => {
const [state] = useState(() => new ComponentLocalState());
return (
<div>
<div>counter: {state.counter}</div>
<button onClick={state.incr}>incr</button>
<button onClick={state.decr}>decr</button>
<input onChange={state.handleFirstNameChange} value={state.firstName} placeholder="First name" />
<input onChange={state.handleLastNameChange} value={state.lastName} placeholder="Last name" />
</div>
);
});
Конкретно тут я вижу только 1 простой выход — передавать в onChange не объект, а колбек. Вроде того, который передаётся в setState.
Ну и да, вариант "отобрать состояние у React и отдать его MobX" тоже решит эту проблему. Только, разумеется, не надо смешивать обработчики событий и вью-модель как сделано в комментарии выше.
Да, идея хорошая. Правда мой пример шире изменения состояния. Например, есть какие-то данные, которые нужно использовать в useCallback. Вариантов несколько: можно передавать эти данные в качестве аргумента или указать эти данные в массиве зависимостей useCallback, но порой очень не хватает классического замыкания и useRef позволяет нам воссоздать этот механизм.
Только, разумеется, не надо смешивать обработчики событий и вью-модель как сделано в комментарии выше.
С чего это вдруг?
Прием с useRef предполагает использование value и обработчиков в одном компоненте, который принимает value и onChange, в контексте задачи будет работать хорошо.
Если использовать Suspense, да могут возникнуть ошибки, но при желании можно сломать все что угодно. Важно понимать ограничения и где могут возникать ошибки и я благодарен, что обратили на это внимание. Рассказать обо всех вариантах стрельбы ногам не хватит, ни времени, ни текста.
React hooks, как не выстрелить себе в ноги. Часть 3.2: useMemo, useCallback