I have a custom hook that return an object by parameter that it gets, I need to recreate this with any updated parameter so I need to do that inside useEffect
but I can’t call the hook inside useEffect. Any idea how to implement it?
The custom hook:
useBuilder.tsx
export default function useBuilder(user) {
const api = useGlobalApi()
const user = ...
// doing a lot of requests and logic here that depends on the current user
...
return builder
}
For each selected user I need a new builder
object constructed and returned from the custom hook depends on the selected user.
The usage:
Api.tsx
export default function User() {
const [users, setUsers] = useState([])
const [user, setUser] = useState({})
const [builder, setBuilder] = useState({})
const usersData = api.get('/../users')
useEffect(() => {
if (!usersData?.length) return
setUsers(usersData)
setUser(usersData[0])
}, [usersData])
useEffect(() => {
const builder = useBuilder(user)
setBuilder(builder)
}, [user])
return (
<Select
value={user}
onChange={e => {
setUser(user)
}}
>
{users.map(user => (
<MenuItem key={user.id} value={user}>
{user.name}
</MenuItem>
))}
</Select>
)
}
I’m getting this error:
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
- You might have mismatching versions of React and the renderer (such as React DOM)
- You might be breaking the Rules of Hooks
- You might have more than one copy of React in the same app`
Any idea how can I resolve this and get the expected result?
Edit:
I want to avoid touching the custom hook since this is a global custom hook with a lot of usages.
3
Answers
You need to write a function component that returns the custom hook. The use… prefix only obeys the hook rules when in a function.
Read the docs:react docs
Remove the effect where you call
useBuilder
, just call the custom hook at the top level of your component. However, the custom hook will be called when either theusers
oruser
state variable changes, but you should still get the result that you want sinceuseBuilder
does its logic based only on theuser
.