Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"useState" cannot be called inside a callback. How to use state on "useCallback"?

I want to update state in Child component but it doesn't work. Actually, there're a lot of items. And I want to list each item with map.

The error:

React Hook "useState" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function

The code:

const renderItems = useCallback(() => {
  return items.map((item, idx) => {
    const { name } = room
    const [isCopiedURL, setIsCopiedURL] = useState(false)

    return (
      <li key={idx}>
        <CopyToClipboard
          text={item.name}
          onCopy={() => setIsCopiedURL(true)}
        >
          {item.name}
        </CopyToClipboard>
      </li>
    )
  })
}, [items])
like image 742
k10a Avatar asked May 28 '20 07:05

k10a


People also ask

How do I pass callback useState?

To use callback in the useState hook, we need to use the useEffect hook that triggers after state update and call the function after that. We need to pass state in the useEffect Dependency Array. useEffect is triggered when the state updates and then calls the inside function immediately.

Should I wrap setState in useCallback?

We must remember is that the setState function must not be passed to the useCallback dependency array. The React team suggests this: "React guarantees that setState function identity is stable and won't change on re-renders. This is why it's safe to omit from the useEffect or useCallback dependency list."

Does useCallback cause re render?

The key takeaway here is that useCallback returns you a new version of your function only when its dependencies change, saving your child components from automatically re-rendering every time the parent renders.


1 Answers

You can convert the mapped return value to a component and then use useState within it since hooks are meant to be used within functional components.

According to the rules of rules you can use them within functions such as map in your case

const Item = ({room, item}) => {
    const { name } = room
    const [isCopiedURL, setIsCopiedURL] = useState(false)

    return (
      <li key={idx}>
        <CopyToClipboard
          text={item.name}
          onCopy={() => setIsCopiedURL(true)}
        >
          {item.name}
        </CopyToClipboard>
      </li>
    )
}

...
const renderItems = useCallback(() => {
  return items.map((item, idx) => {
     return <Item room={room} item={item} key={idx} />
  })
}, [items])
...
like image 52
Shubham Khatri Avatar answered Oct 04 '22 21:10

Shubham Khatri