Closed jamesdbrock closed 4 years ago
It's not exactly that React needs certain operations to be called in a certain order. It's more that React uses the order in which hooks are run as a way of tracking them, and associates internal React state with each hook. This means that if the order of hook evaluation changes in a component then the behaviour is undefined and likely highly unsafe (unless React provides some guarantees about this, but I don't think they do).
Render
is just an indexed monad that represents Effect
s, but the restrictions are modelled by Hook
:
type Hook (newHook :: Type -> Type) a
= forall hooks. Render hooks (newHook hooks) a
Like Phil was using tuples to build up the sequence of hooks, react-basic-hooks
uses newtypes and Render
:
customHook :: forall hooks. Render hooks (UseEffect Number (UseMemo Boolean Int (UseState String hooks))) Unit
customHook = React.do
_ <- React.useState "hi"
_ <- React.useMemo false \_ -> 1
React.useEffect 22.2 mempty
pure unit
Thank you @robertdp .
Here's the reference to the rule which is enforced by the Hook
type. This is why we need the indexed monad Render
.
https://reactjs.org/docs/hooks-rules.html
React relies on the order in which Hooks are called.
ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple
useState
anduseEffect
calls.
Yep -- implementing React hooks with plain monads would still allow broken hook rules. Using indexed monads captures the same rules in the type system that eslint-plugin-react-hooks
does in JS, except dependency list tracking.
And also, for those following along, react-basic-hooks recommends the “qualified-do” syntax because then we can write do
blocks with the indexed monad Render
.
https://pursuit.purescript.org/packages/purescript-react-basic-hooks/docs/React.Basic.Hooks#v:bind
https://twitter.com/paf31/status/1197185171176341504
https://twitter.com/paf31/status/1231614635754819584
https://twitter.com/paf31/status/1231614926503993345
I sure wish I could find that blog post. I don't think it exists?
I had a conversation last week which I will paraphrase like this:
Me: Why does react-basic-hooks need indexed monads?
@robertdp : Because React needs certain operations to be called in a certain order, and the indexed
Render
monad enforces that ordering at the type level.Which makes sense, and it also seems to be what Phil is describing on Twitter. But I would like to understand it better. Which React “restrictions on hooks”, exactly, are captured by
Render
?