简体   繁体   English

在组件道具中使用 React.useMemo 或 React.useCallback 好吗?

[英]Is good to use React.useMemo or React.useCallback inside component props?

I was thinking about how to code TailwindCSS cleaner in React.我在考虑如何在 React 中编写 TailwindCSS cleaner。 Since Tailwind is utility-first, it makes us inevitably end up with components (ex: className="w-full bg-red-500" ).由于 Tailwind 是实用程序优先的,它使我们不可避免地以组件结束(例如: className="w-full bg-red-500" )。 So, I tried to create a utility like this:所以,我试图创建一个这样的实用程序:
utils/tailwind.ts

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

and call it inside:并在里面调用它:
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>
  )
}

But, it will cause tw() to be re-called as always as text state is updated.但是,它会导致tw()text state 更新时一如既往地被重新调用。

So, I decided to wrap tw() function using useMemo to prevent re-call since the tw() always returns the same value.因此,我决定使用 useMemo 包装tw() useMemo以防止重新调用,因为tw()始终返回相同的值。 But the code is like this:但是代码是这样的:

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>
  )
}

Is it correct or good practice if I put useMemo like that?如果我这样使用useMemo是正确的还是好的做法? Thank you.谢谢你。

Is it correct or good practice if I put useMemo like that?如果我这样使用 useMemo 是正确的还是好的做法?

Short answer - yes .简短的回答 - yes的。

Long answer - it depends.长答案 - 这取决于。 It depends on how heavy the operation is.这取决于手术的重量。 In your particular case, joining a couple of strings may not be such heavy calculation to make the useMemo worth to be used - it's good to remember that useMemo memoizes stuff and it takes memory.在您的特定情况下,连接几个字符串可能不会是使useMemo值得使用的繁重计算 - 最好记住useMemo记住东西,它需要 memory。

Consider example below.考虑下面的例子。 In the first case, without useMemo , the tw function will be called with every App re-render, to calculate new className .在第一种情况下,没有useMemo时, tw function 将在每次App重新渲染时被调用,以计算新的className However, if useMemo is used (with empty dependency array ), tw will not be called and new className will not be calculated even if the App re-renders, due to the basic memoization .但是,如果使用useMemo依赖项数组为空),由于基本的className ,即使App重新呈现,也不会调用tw并且不会计算新的名。 It will be called only once , on component mount.它只会在组件安装时被调用一次

Conclusion - it's a good practice to use useMemo , but rather for heavy operations, like mapping or reducing huge arrays.结论 - 使用useMemo是一种很好的做法,但更适合繁重的操作,例如映射或减少巨大的 arrays。

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>
  );
}

Playground: https://codesandbox.io/s/distracted-liskov-tfm72c?file=/src/App.tsx游乐场: https://codesandbox.io/s/distracted-liskov-tfm72c?file=/src/App.tsx

The issue here is that React will re-render the component every time it's state changes.这里的问题是 React 会在每次 state 发生变化时重新渲染组件。 (each time you setText). (每次你设置文本)。

If you want to prevent that from happening, then see if you really need this re-render hence what do you really need the input text for?如果你想防止这种情况发生,那么看看你是否真的需要重新渲染,那么你真正需要输入文本的目的是什么?

you do not HAVE to use state here to use the input value.您不必在此处使用 state 来使用输入值。 you could call another function on change which will not update the state, and use the input value there for whatever you need.您可以在更改时调用另一个 function,它不会更新 state,并根据需要使用那里的输入值。 for example:例如:

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>
  )
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM