I was thinking about how to code TailwindCSS cleaner in React. Since Tailwind is utility-first, it makes us inevitably end up with components (ex: 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.
So, I decided to wrap tw() function using useMemo to prevent re-call since the tw() always returns the same value. 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? Thank you .
Short answer -
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
useMemoworth to be used - it's good to remember thatuseMemomemoizes stuff and it takes memory.Consider example below. In the first case, without
useMemo, thetwfunction will be called with everyAppre-render, to calculate newclassName. However, ifuseMemois used (with empty dependency array),twwill not be called and newclassNamewill not be calculated even if theAppre-renders, due to the basic memoization. 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.Playground: https://codesandbox.io/s/distracted-liskov-tfm72c?file=/src/App.tsx