Pull to refresh

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, да могут возникнуть ошибки, но при желании можно сломать все что угодно. Важно понимать ограничения и где могут возникать ошибки и я благодарен, что обратили на это внимание. Рассказать обо всех вариантах стрельбы ногам не хватит, ни времени, ни текста.

Sign up to leave a comment.