Когда реквизит содержит только onChange
и никаких других элементов, не требуется ли useCallback
в этом случае, поскольку весь компонент уже запомнен на основе onChange
?
Запоминание основано на всех реквизитах, а не только на onChange
. Да, useCallback
здесь не нужен.
Если мы добавим дополнительную опору (скажем, value
для начального значения для <input>
), то я думаю, что useCallback
станет полезным, поскольку в противном случае handleChange
будет воссоздан, даже если onChange
не изменится, но значение изменится. Это правильно?
Если вы хотите обновить value
, а не onChange
при обновлении input
, вы должны добавить value
к своим реквизитам и продолжать использовать useCallback
для вашего handleChange
(если хотите, чтобы React не заменял новый обработчик событий при установке значения; у меня такое впечатление, что это часто излишне). Например:
const UserInput = React.memo(({ onChange, value }: UserInputProps) => {
const handleChange = useCallback(
(event) => {
onChange(event.target.value);
},
[onChange]
);
return <input type="text" value={value} onChange={handleChange} />;
});
Это будет использовать последнюю value
и повторно использовать предыдущий handleChange
, если свойство onChange
не изменилось.
Вы можете не оставить React.memo
в этом случае, если вы ожидаете, что value
будет изменено в результате onChange
. То есть, если вы ожидаете, что в общем случае value
будет отличаться каждый раз при вызове вашего компонента, тогда проверка свойств React.memo
будет дополнительной работой, которую вы можете не выполнять:
const UserInput = ({ onChange, value }: UserInputProps) => {
const handleChange = useCallback(
(event) => {
onChange(event.target.value);
},
[onChange]
);
return <input type="text" value={value} onChange={handleChange} />;
};
Но вы можете оставить его, если хотите, чтобы React.memo
продолжал проверять реквизиты и не вызывать вашу функцию, когда ни одна из них не меняется.
Если вы просто хотите чтобы предоставить компоненту начальное значение, а затем управлять им локально, вы можете продолжать использовать React.memo
(поскольку он по-прежнему отображает то же самое для тех же входных реквизитов), в этом случае вы этого не сделаете. need useCallback
:
const UserInput = React.memo(({ onChange, initialValue }: UserInputProps) => {
const [value, setValue] = useState(initialValue);
const handleChange = (event) => {
setValue(event.target.value);
onChange(event.target.value);
};
return <input type="text" value={value} onChange={handleChange} />;
});
Это будет вызвано только при изменении onChange
или initialValue
. Вы также можете использовать здесь useCallback
, чтобы, опять же, обновлять onChange
на input
при изменении свойства onChange
, чтобы React не удалял старый обработчик и не устанавливал новый, когда только value
изменения:
const UserInput = React.memo(({ onChange, initialValue }: UserInputProps) => {
const [value, setValue] = useState(initialValue);
const handleChange = useCallback(
(event) => {
setValue(event.target.value);
onChange(event.target.value);
},
[onChange]
);
return <input type="text" value={value} onChange={handleChange} />;
});
Примечание: нужно помнить, что новая функция handleChange
создается каждый раз, когда вызывается функция вашего компонента, даже если вы используете useCallback
. Он должен быть таким, чтобы его можно было передать в useCallback
в качестве аргумента. Единственная разница заключается в том, используете ли вы эту новую функцию или исходную, которая была создана в первый раз (результат useCallback
). Я думаю, что причиной повторного использования первого, созданного для данного набора зависимостей, является минимизация изменений, передаваемых дочерним компонентам.