Я использую useCallback для запоминания моей функции обратного вызова, но, похоже, она не работает с функцией каррирования, мой компонент PhotoItem всегда перерисовывается при повторном рендеринге MyListPhoto, хотя я оборачиваю свой PhotoItem в React.memo(). Поскольку функция handleDelete является каррирующей, есть ли способ использовать ее с useCallback?
const MyListPhoto = () => {
...other state...
const { delete } = useDeletePhoto();
// always create new function when component re-render
const handleDelete = useCallback((index) => (photoId) => {
delete(photoId, index)
}, []);
return (
<ul>
{photos.map((photo, index) => (
<PhotoItem
key = {photo.id}
photo = {photo}
onDelete = {handleDelete(index)}
/>
))}
</ul>
)
}
Компонент PhotoItem:
const PhotoItem = React.memo(({ photo, onDelete }) => {
console.info('re-render');
return (
...
)
})
@Konrad Я обновил свой вопрос. Помогите мне проверить это
@Konrad useCallback не работает с функцией каррирования, верно?
Вы каждый раз создаете новую функцию, поэтому она не может работать
handleDelete всегда будет одной и той же функцией при каждом рендеринге, вопреки тому, что вы говорите - проблема в том, что вызов ее при каждом рендеринге для получения handleDelete(index) действительно является новой ссылкой на функцию каждый раз, когда это делается. На самом деле это не имеет ничего общего с useCallback или каррированием, каждый раз, когда вы определяете обработчик событий или другую вспомогательную функцию в результате вызова функции, это произойдет.
Что такое photoId? Вам даже нужно передать index в delete?
@Bergi да, мне нужно пройти и index, и photoId, чтобы удалить
@Эппл Но почему? Идентификатора должно быть достаточно. Удаление параметра index избавит вас от многих проблем.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы должны запомнить каждую функцию
const MyListPhoto = () => {
// ...other state...
const { del } = useDeletePhoto();
const deleteHandlers = useMemo(() => {
return photos.map((photo, index) => (photoId) => del(photoId, index));
}, [photos]);
return (
<ul>
{photos.map((photo, index) => (
<PhotoItem
key = {photo.id}
photo = {photo}
onDelete = {deleteHandlers[index]}
/>
))}
</ul>
);
};
Спасибо @Konrad, у меня есть вопрос, почему мы не можем использовать useCallback в этом случае?
Потому что useCallback возвращает одну функцию, а вам нужно столько же функций, сколько photos.length
спасибо за ваш отличный ответ, это легко понять.
На самом деле достаточно использовать photos.length в качестве зависимости, так как функции на самом деле не зависят от самого значения photo. Но он все равно будет повторно отображать все <PhotoItem> при изменении массива (длины).
@Bergi Я буду ссылаться на другой способ, кажется, что способ, который я реализую, действительно неэффективен.
Честно говоря, это хорошая идея, и я проголосовал, но я думаю, что нет необходимости запоминать массив с n функциями, особенно когда n велико, на самом деле нам не нужно ничего запоминать, но оператор хочет запомнить, так что запоминания только одной функции достаточно, не так ли? ваша реализация выглядит более безопасной, но, поскольку вы заканчиваете тем, что передаете индекс или его основную функцию каждому дочернему элементу, поэтому мы возвращаемся к той же точке, что и достаточно. надеюсь вы поняли мою мысль ^^
Извините, я не понял сути! Зачем нужно запоминать функцию? как насчет этого:
...
return <ul>
{photos.map((photo, index) => (
<PhotoItem key = {photo.id} photo = {photo} onDelete = {() => delete(photo.id, index)} />
</ul>
)
Он будет перерисовывать каждый компонент PhotoItem каждый раз, когда изменяется состояние.
это потому, что вы создаете новый PhotoItem в функции карты, и у него нет другого выбора
нормально обновлять список после любого изменения
Это потому, что реквизит меняется. ОП использует React.memo, чтобы предотвратить это, но реквизит не может измениться
давайте посмотрим, что я делаю, мое намерение состоит в том, чтобы сохранить PhotoItems в map цикле, а не повторно рендерить с помощью мемоизированной onDelete опоры. Зачем это делать? Потому что каждый раз MyListPhoto повторный рендеринг, если я не использую useCallback, это приводит к onDelete созданию новой функции, даже если onDelete обратный вызов не срабатывает, поэтому React скажет: «О, onDelete реквизит изменился. Я перерендерю ваш компонент».
Привет @ParsaS, ты понял мою точку зрения?
Покажите, как вы его заворачиваете, используя
React.memo