https://github.com/purescript-react/purescript-react-basic-hooks
An implementation of React hooks on top of purescript-react-basic
https://github.com/purescript-react/purescript-react-basic-hooks
Last synced: 3 months ago
JSON representation
An implementation of React hooks on top of purescript-react-basic
- Host: GitHub
- URL: https://github.com/purescript-react/purescript-react-basic-hooks
- Owner: purescript-react
- License: apache-2.0
- Created: 2019-01-15T07:49:50.000Z (over 7 years ago)
- Default Branch: main
- Last Pushed: 2024-11-03T12:06:12.000Z (over 1 year ago)
- Last Synced: 2026-01-13T14:48:03.389Z (3 months ago)
- Language: PureScript
- Homepage: https://pursuit.purescript.org/packages/purescript-react-basic-hooks/
- Size: 558 KB
- Stars: 203
- Watchers: 9
- Forks: 32
- Open Issues: 11
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-purescript - react-basic-hooks - React hook API for react-basic. (UI / React)
README
# react-basic-hooks [](https://github.com/spicydonuts/purescript-react-basic-hooks/actions/workflows/node.js.yml)
`react-basic-hooks` is a React hook API for [react-basic](https://github.com/lumihq/purescript-react-basic).
_Note:_ This library supports React `>=16.8.0` with full React 19 support. For more info on hooks, see [React's documentation](https://react.dev/reference/react).
I recommend using PureScript's "qualified do" syntax whilst using this library (it's used in the examples, the `React.do` bits).
It became available in the `0.12.2` compiler release.
This library provides the `React.Basic.Hooks` module, which can completely replace the `React.Basic` module.
It borrows a few types from the current `React.Basic` module like `ReactComponent` and `JSX` to make it easy to use both versions in the same project.
If we prefer this API over the existing react-basic API, we may eventually replace `React.Basic` with this implementation.
## React Version Support
- **React 16.8+**: Core hooks (useState, useEffect, useReducer, useRef, useContext, useMemo, useDebugValue, useLayoutEffect)
- **React 18+**: useId, useTransition, useDeferredValue, useSyncExternalStore, useInsertionEffect
- **React 19+**: useOptimistic, useActionState, useEffectEvent (experimental)
## Example
```purs
mkCounter :: Component Int
mkCounter = do
component "Counter" \initialValue -> React.do
counter /\ setCounter <- useState initialValue
pure
$ R.button
{ onClick: handler_ do
setCounter (_ + 1)
, children:
[ R.text $ "Increment: " <> show counter ]
}
```
## React 19 Hooks
### useOptimistic
Optimistically update the UI whilst waiting for an async action to complete. The optimistic state automatically reverts to the actual state when the action finishes.
```purs
mkMessageList :: Component Props
mkMessageList = do
component "MessageList" \{ messages } -> React.do
optimisticMessages /\ addOptimisticMessage <- useOptimistic messages \state newMessage ->
Array.snoc state newMessage
isPending /\ startTransition <- useTransition
let handleSend message = startTransition do
addOptimisticMessage message
-- Async operation to send message to server
sendToServer message
pure $ R.div_ (map renderMessage optimisticMessages)
```
### useActionState
Manage form actions with built-in pending state. The action function receives the previous state and form data, making it ideal for form submissions. Uses Effect for synchronous operations.
```purs
mkForm :: Component Unit
mkForm = do
component "Form" \_ -> React.do
state /\ (formAction /\ isPending) <- useActionState initialState updateFn
where
updateFn prevState formData = do
-- Process form submission (Effect version)
result <- submitToServer formData
pure (Result.fromEither result)
pure $ R.button
{ disabled: isPending
, onClick: handler_ (formAction myFormData)
, children: [ R.text if isPending then "Submitting..." else "Submit" ]
}
```
For progressive enhancement (form works without JavaScript), use `useActionStateWithPermalink`:
```purs
state /\ (formAction /\ isPending) <- useActionStateWithPermalink initialState updateFn "/api/submit"
pure $ R.form
{ action: formAction -- Falls back to /api/submit without JS
, children: [ ... ]
}
```
### useAffActionState
Aff version of `useActionState` for async operations. Available in `React.Basic.Hooks.Aff`. Uses Aff for natural async handling.
```purs
import React.Basic.Hooks.Aff (useAffActionState)
mkForm :: Component Unit
mkForm = do
component "Form" \_ -> React.do
state /\ (formAction /\ isPending) <- useAffActionState initialState affFn
where
affFn prevState formData = do
-- Process form submission (Aff version - natural async!)
result <- Aff.submitToServer formData
pure (Result.fromEither result)
pure $ R.button
{ disabled: isPending
, onClick: handler_ (formAction myFormData)
, children: [ R.text if isPending then "Submitting..." else "Submit" ]
}
```
With permalink: `useAffActionStateWithPermalink initialState affFn "/api/submit"`
### useEffectEvent
Extract non-reactive logic from Effects. The returned function can access the latest props and state without causing the Effect to re-run when those values change.
```purs
mkComponent :: Component Props
mkComponent = do
component "Component" \{ url, onSuccess } -> React.do
count /\ setCount <- useState 0
-- onSuccess can use the latest count without re-running the effect
onSuccessEvent <- useEffectEvent \data -> do
onSuccess data count
-- Effect only re-runs when url changes, not when count changes
useEffect url do
response <- fetchData url
onSuccessEvent response
pure mempty
pure $ R.div_ [ ... ]
```
## Available Hooks
### Core Hooks (React 16.8+)
- `useState` / `useState'` — State management
- `useEffect` / `useEffectOnce` / `useEffectAlways` — Side effects
- `useLayoutEffect` — Synchronous layout effects
- `useReducer` — State management with reducers
- `useRef` — Mutable refs
- `useContext` — Context consumption
- `useMemo` — Memoised computation
- `useDebugValue` — DevTools debugging labels
### React 18 Hooks
- `useId` — Unique ID generation
- `useTransition` — Concurrent transitions
- `useDeferredValue` — Deferred value updates
- `useSyncExternalStore` — External store synchronisation
- `useInsertionEffect` — DOM mutation effects
### React 19 Hooks
- `useOptimistic` — Optimistic UI updates
- `useActionState` — Form action management
- `useEffectEvent` — Non-reactive effect logic (experimental)
### Additional Features
- `memo` / `memo'` — Component memoisation
- `component` — Component creation
- Custom hooks via `React.Basic.Hooks.Aff` for async effects
- `React.Basic.Hooks.Suspense` for Suspense support
- `React.Basic.Hooks.ErrorBoundary` for error boundaries
```