Как использовать useCallback с функцией каррирования в React?

Я использую 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 (
      ...
    )
})

Покажите, как вы его заворачиваете, используя React.memo

Konrad 23.07.2023 14:20

@Konrad Я обновил свой вопрос. Помогите мне проверить это

Epple 23.07.2023 14:22

@Konrad useCallback не работает с функцией каррирования, верно?

Epple 23.07.2023 14:39

Вы каждый раз создаете новую функцию, поэтому она не может работать

Konrad 23.07.2023 14:43
handleDelete всегда будет одной и той же функцией при каждом рендеринге, вопреки тому, что вы говорите - проблема в том, что вызов ее при каждом рендеринге для получения handleDelete(index) действительно является новой ссылкой на функцию каждый раз, когда это делается. На самом деле это не имеет ничего общего с useCallback или каррированием, каждый раз, когда вы определяете обработчик событий или другую вспомогательную функцию в результате вызова функции, это произойдет.
Robin Zigmond 23.07.2023 14:44

Что такое photoId? Вам даже нужно передать index в delete?

Bergi 23.07.2023 15:01

@Bergi да, мне нужно пройти и index, и photoId, чтобы удалить

Epple 23.07.2023 15:03

@Эппл Но почему? Идентификатора должно быть достаточно. Удаление параметра index избавит вас от многих проблем.

Bergi 23.07.2023 15:05
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
8
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы должны запомнить каждую функцию

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 в этом случае?

Epple 23.07.2023 14:51

Потому что useCallback возвращает одну функцию, а вам нужно столько же функций, сколько photos.length

Konrad 23.07.2023 14:56

спасибо за ваш отличный ответ, это легко понять.

Epple 23.07.2023 15:02

На самом деле достаточно использовать photos.length в качестве зависимости, так как функции на самом деле не зависят от самого значения photo. Но он все равно будет повторно отображать все <PhotoItem> при изменении массива (длины).

Bergi 23.07.2023 15:03

@Bergi Я буду ссылаться на другой способ, кажется, что способ, который я реализую, действительно неэффективен.

Epple 23.07.2023 15:09

Честно говоря, это хорошая идея, и я проголосовал, но я думаю, что нет необходимости запоминать массив с n функциями, особенно когда n велико, на самом деле нам не нужно ничего запоминать, но оператор хочет запомнить, так что запоминания только одной функции достаточно, не так ли? ваша реализация выглядит более безопасной, но, поскольку вы заканчиваете тем, что передаете индекс или его основную функцию каждому дочернему элементу, поэтому мы возвращаемся к той же точке, что и достаточно. надеюсь вы поняли мою мысль ^^

Hatana 23.07.2023 15:32

Извините, я не понял сути! Зачем нужно запоминать функцию? как насчет этого:

...
return <ul>
        {photos.map((photo, index) => (
           <PhotoItem key = {photo.id} photo = {photo} onDelete = {() => delete(photo.id, index)}  />
     </ul>
   )

Он будет перерисовывать каждый компонент PhotoItem каждый раз, когда изменяется состояние.

Konrad 23.07.2023 15:56

это потому, что вы создаете новый PhotoItem в функции карты, и у него нет другого выбора

Parsa S 23.07.2023 15:58

нормально обновлять список после любого изменения

Parsa S 23.07.2023 15:59

Это потому, что реквизит меняется. ОП использует React.memo, чтобы предотвратить это, но реквизит не может измениться

Konrad 23.07.2023 16:06

давайте посмотрим, что я делаю, мое намерение состоит в том, чтобы сохранить PhotoItems в map цикле, а не повторно рендерить с помощью мемоизированной onDelete опоры. Зачем это делать? Потому что каждый раз MyListPhoto повторный рендеринг, если я не использую useCallback, это приводит к onDelete созданию новой функции, даже если onDelete обратный вызов не срабатывает, поэтому React скажет: «О, onDelete реквизит изменился. Я перерендерю ваш компонент».

Epple 23.07.2023 16:27

Привет @ParsaS, ты понял мою точку зрения?

Epple 23.07.2023 16:33

Другие вопросы по теме