Хорошо ли использовать React.useMemo или React.useCallback внутри свойств компонента?

Я думал о том, как закодировать очиститель TailwindCSS в React. Поскольку Tailwind ориентирован на полезность, это неизбежно приводит к тому, что мы получаем компоненты (например, className = "w-full bg-red-500"). Итак, я попытался создать такую ​​утилиту:
utils/tailwind.ts

const tw = (...classes: string[]) => classes.join(' ')

и назовите это внутри:
components/Example.tsx

import { useState } from 'react'
import tw from '../utils/tailwind'

const Example = () => {
  const [text, setText] = useState('')

  return (
    <div>
      <input onChange = {(e: any) => setText(e.target.value)} />
      <div
        className = {tw(
          'w-full',
          'h-full',
          'bg-red-500'
        )}
      >
        hello
      </div>
    </div>
  )
}

Но это приведет к повторному вызову tw(), как всегда, по мере обновления состояния text.

Итак, я решил обернуть функцию tw(), используя useMemo, чтобы предотвратить повторный вызов, поскольку tw() всегда возвращает одно и то же значение. Но код такой:

import { useState, useMemo } from 'react'
import tw from '../utils/tailwind'

const Example = () => {
  const [text, setText] = useState('')

  return (
    <div>
      <input onChange = {(e: any) => setText(e.target.value)} />
      <div
        className = {useMemo(() => tw(
          'w-full',
          'h-full',
          'bg-red-500'
        ), [])}
      >
        hello
      </div>
    </div>
  )
}

Это правильно или хорошая практика, если я ставлю useMemo вот так? Спасибо 🙏 .

Вызов его внутри синтаксиса элемента JSX аналогичен вызову перед выражением return, сохранению результата во временной переменной и передаче его в качестве значения атрибута. Нет разницы. Конечно, правила хуков все еще применяются, вы не можете сделать это в условном рендеринге.

Bergi 20.11.2022 03:32
Поведение ключевого слова "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) для оценки ваших знаний,...
4
1
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Это правильно или хорошая практика, если я так использую useMemo?

Краткий ответ - yes.

Длинный ответ - это зависит. Это зависит от того, насколько тяжелая операция. В вашем конкретном случае объединение нескольких строк может быть не таким сложным расчетом, чтобы использовать useMemo ценность - хорошо помнить, что useMemo запоминает материал и требует памяти.

Рассмотрим пример ниже. В первом случае, без useMemo, функция tw будет вызываться при каждом App повторном рендеринге для вычисления нового className. Однако, если используется useMemo (с пустым массивом зависимостей), tw не будет вызываться, а новый className не будет рассчитываться, даже если App будет повторно отображаться из-за базовой мемоизации. Он будет вызываться только один раз при монтировании компонента.

Вывод — useMemo рекомендуется использовать, но скорее для тяжелых операций, таких как сопоставление или сокращение огромных массивов.

export default function App() {
  const [_, s] = useState(0);

  return (
    <div className = "App">
      <div className = {tw(false, 'w-full', 'h-full', 'bg-red-500')}>div1</div>
      <div
        className = {useMemo(
          () => tw(true, 'w-full', 'h-full', 'bg-red-500'),
          [],
        )}
      >
        div2
      </div>

      <button onClick = {() => s(Math.random())}>re-render</button>
    </div>
  );
}

Детская площадка: https://codesandbox.io/s/distracted-liskov-tfm72c?file=/src/App.tsx

Спасибо @kind user 🙏. Итак, если проект будет больше и поскольку useMemo занимает память, функция tw() всегда только объединяет строки, так какой из них вы предпочитаете? использовать useMemo или нет? Спасибо 😊 .

mnrendra 20.11.2022 05:58

@mnrendra Лично я бы не стал использовать useMemo для соединения строк. Вернее, как я уже упоминал выше — на сопоставлении или уменьшении огромных массивов. Но все же это зависит от того, сколько элементов вы соединяете. Если о сотнях - достойно точно. Если только пару - то нет. (Комментарий отредактирован)

kind user 22.11.2022 01:02

Проблема здесь в том, что React будет повторно отображать компонент каждый раз, когда его состояние изменяется. (каждый раз, когда вы устанавливаете текст).

Если вы хотите предотвратить это, посмотрите, действительно ли вам нужен этот повторный рендеринг, поэтому для чего вам действительно нужен входной текст?

вы НЕ ДОЛЖНЫ использовать состояние здесь, чтобы использовать входное значение. вы можете вызвать другую функцию при изменении, которая не будет обновлять состояние, и использовать там входное значение для всего, что вам нужно. Например:

const Example = () => {

  const onInputChange = (e) => {
    const text = e.target.value

    // do something with text
  }


  return (
    <div>
      <input onChange = {(e: any) => onInputChange(e)} />
      <div
        className = {useMemo(() => tw(
          'w-full',
          'h-full',
          'bg-red-500'
        ), [])}
      >
        hello
      </div>
    </div>
  )
}

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