Module

React.Basic.Hooks.Internal

Package
purescript-react-basic-hooks
Repository
spicydonuts/purescript-react-basic-hooks

#Render Source

newtype Render x y a

Render represents the effects allowed within a React component's body, i.e. during "render". This includes hooks and ends with returning JSX (see pure), but does not allow arbitrary side effects.

The x and y type arguments represent the stack of effects that this Render implements, with x being the stack at the start of this Render, and y the stack at the end.

See purescript-indexed-monad to understand how the order of the stack is enforced at the type level.

Instances

#coerceHook Source

coerceHook :: forall a newHook oldHook hooks. Newtype newHook oldHook => Render hooks oldHook a -> Render hooks newHook a

Rename/alias a chain of hooks. Useful for exposing a single "clean" type when creating a hook to improve error messages and hide implementation details, particularly for libraries hiding internal info.

For example, the following alias is technically correct but when inspecting types or error messages the alias is expanded to the full original type and UseAff is never seen:

type UseAff deps a hooks
  = UseEffect deps (UseState (Result a) hooks)

useAff :: ... -> Hook (UseAff deps a) (Result a)
useAff deps aff = React.do
  ...

coerceHook allows the same code to safely export a newtype instead, hiding the internal implementation:

newtype UseAff deps a hooks
  = UseAff (UseEffect deps (UseState (Result a) hooks))

derive instance ntUseAff :: Newtype (UseAff deps a hooks) _

useAff :: ... -> Hook (UseAff deps a) (Result a)
useAff deps aff = coerceHook React.do
  ...

#unsafeHook Source

unsafeHook :: forall a newHook. Effect a -> Hook newHook a

Promote an arbitrary Effect to a Hook.

This is unsafe because it allows arbitrary effects to be performed during a render, which may cause them to be run many times by React. This function is primarily for constructing new hooks using the FFI. If you just want to alias a safe hook's effects, prefer coerceHook.

It's also unsafe because the author of the hook type (the newHook type variable used here) MUST contain all relevant types. For example, UseState has a phantom type to track the type of the value contained. useEffect tracks the type used as the deps. useAff tracks both the deps and the resulting response's type. Forgetting to do this allows the consumer to reorder hook effects. If useState didn't track the return type the following extremely unsafe code would be allowed:

React.do
  if xyz then
    _ <- useState 0
    useState Nothing
  else
    s <- useState Nothing
    _ <- useState 0
    pure s
  ...

The same applies to deps in these examples as they use Eq and a reorder would allow React to pass incorrect types into the eq function!

#unsafeRenderEffect Source

unsafeRenderEffect :: forall a. Effect a -> Pure a

Promote an arbitrary Effect to a Pure render effect.

This is unsafe because it allows arbitrary effects to be performed during a render, which may cause them to be run many times by React. You should almost always prefer useEffect!

#Pure Source

type Pure a = forall hooks. Render hooks hooks a

Type alias used to lift otherwise pure functionality into the Render type. Not commonly used.

#Hook Source

type Hook (newHook :: Type -> Type) a = forall hooks. Render hooks (newHook hooks) a

Type alias for Render representing a hook.

The newHook argument is a type constructor which takes a set of existing effects and generates a type with a new set of effects (produced by this hook) stacked on top.

#bind Source

bind :: forall m z y x b a. IxBind m => m x y a -> (a -> m y z b) -> m x z b

Exported for use with qualified-do syntax

#discard Source

discard :: forall m z y x b a. IxBind m => m x y a -> (a -> m y z b) -> m x z b

Exported for use with qualified-do syntax

#HookApply Source

type HookApply hooks (newHook :: Type -> Type) = newHook hooks

#type (&) Source

Operator alias for React.Basic.Hooks.Internal.HookApply (left-associative / precedence 0)

Applies a new hook to a hook chain, with the innermost hook as the left argument. This allows hook chains to be written in reverse order, aligning them with the order they appear when actually used in do-notation.

type UseCustomHook hooks = UseEffect String (UseState Int hooks)
type UseCustomHook' = UseState Int & UseEffect String