Create function components using powerful and composable hooks.
If you know and love hooks from React, you already know the main API of OuterHooks as they are very alike.
- OuterHooks is plain JavaScript/TypeScript
- No JSX here – does not render to the DOM or any UI really
- Only compose logic using native & custom hooks
- Life cycle hooks like useEffect also run in Node
yarn add @xiel/outer-hooks
This library is still in beta. It works, is well tested and actively being developed. But the API is not 100% stable yet.
- useState, useRef, useMemo, useCallback, useReducer, useEffect, useLayoutEffect, ...
For now please check the React Hooks API reference as they work exactly the same in OuterHooks.
By composing native hooks, you are creating a custom hook. Native hooks and custom hooks can be composed and nested.
// Define a custom hook
function useCustomHook() {
  const [currentState, setState] = useState(0)
  useEffect(() => {
    if (currentState < 5) {
      setState(currentState + 1)
    }
  }, [currentState])
  return currentState
}
// Run the hook
const custom = runHook(useCustomHook)
// Gets called every time the hook has run
// In this example it will get called with the values 0, 1, 2, 3, 4, 5
custom.on('update', (value) => console.log(value))
// Gets called when the hook was destroyed
custom.on('destroy', (error) => console.error('destroyed'))runHook(fn) returns the following interface, which lets you await the next value, await effects, read the latest value and subscribe to updates to your hook.
export interface Root<Props, HookValue> {
  displayName: string
  /**
   * Resolves once the hooks has rendered.
   * Might resolve after being intermediately suspended.
   */
  value: Promise<HookValue>
  /**
   * Resolves once all side effects have run (cleanups, useLayoutEffects and useEffects)
   */
  effects: Promise<void>
  /**
   * Returns the current value of the ran hook (outermost custom `useXYZ` hook)
   * This might return undefined or a stole/older value while the hook is suspended.
   * Recommended: Use the value promise to get the latest value.
   */
  currentValue?: HookValue
  /**
   * While the hook is suspended, this will return true
   */
  isSuspended: boolean
  /**
   * If the hook was destroyed (by error or externally), this will return true
   */
  isDestroyed: boolean
  /**
   * Resolves after all cleanup functions have run
   */
  isDestroyedPromise: Promise<unknown> | undefined
  /**
   * Re-run the hook with new props
   */
  render: RenderFn<Props, HookValue>
  /**
   * Re-run the hook with (partially) new props.
   */
  update: UpdateFn<Props, HookValue>
  /**
   * Subscribe to hook updates
   */
  on: <T extends keyof SubscriptionTypes>(
    type: T,
    subscription: SubscriptionTypes<HookValue>[T]
  ) => UnsubscribeFn
  /**
   * Unsubscribe from hook updates
   */
  off: <T extends keyof SubscriptionTypes>(
    type: T,
    subscription: SubscriptionTypes<HookValue>[T]
  ) => void
  /**
   * Destroy the hook.
   * This will run all cleanup functions and reject the value promise
   */
  destroy(reason?: unknown): Promise<unknown>
}