{"id":13682440,"url":"https://github.com/purescript-react/purescript-react-basic-hooks","last_synced_at":"2026-02-01T22:09:03.067Z","repository":{"id":38421615,"uuid":"165808163","full_name":"purescript-react/purescript-react-basic-hooks","owner":"purescript-react","description":"An implementation of React hooks on top of purescript-react-basic","archived":false,"fork":false,"pushed_at":"2024-11-03T12:06:12.000Z","size":571,"stargazers_count":203,"open_issues_count":11,"forks_count":32,"subscribers_count":9,"default_branch":"main","last_synced_at":"2026-01-13T14:48:03.389Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://pursuit.purescript.org/packages/purescript-react-basic-hooks/","language":"PureScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/purescript-react.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-01-15T07:49:50.000Z","updated_at":"2025-12-31T04:58:31.000Z","dependencies_parsed_at":"2025-04-30T09:46:05.100Z","dependency_job_id":"71d5eb2f-af3c-4588-a83e-c8d58b17c274","html_url":"https://github.com/purescript-react/purescript-react-basic-hooks","commit_stats":null,"previous_names":["purescript-react/purescript-react-basic-hooks","spicydonuts/purescript-react-basic-hooks","megamaddu/purescript-react-basic-hooks"],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/purescript-react/purescript-react-basic-hooks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-react%2Fpurescript-react-basic-hooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-react%2Fpurescript-react-basic-hooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-react%2Fpurescript-react-basic-hooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-react%2Fpurescript-react-basic-hooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/purescript-react","download_url":"https://codeload.github.com/purescript-react/purescript-react-basic-hooks/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-react%2Fpurescript-react-basic-hooks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28774297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T09:42:00.929Z","status":"ssl_error","status_checked_at":"2026-01-26T09:42:00.591Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T13:01:46.054Z","updated_at":"2026-02-01T22:09:03.063Z","avatar_url":"https://github.com/purescript-react.png","language":"PureScript","readme":"# react-basic-hooks [![Build Status](https://github.com/spicydonuts/purescript-react-basic-hooks/actions/workflows/node.js.yml/badge.svg)](https://github.com/spicydonuts/purescript-react-basic-hooks/actions/workflows/node.js.yml)\n\n`react-basic-hooks` is a React hook API for [react-basic](https://github.com/lumihq/purescript-react-basic).\n\n_Note:_ This library supports React `\u003e=16.8.0` with full React 19 support. For more info on hooks, see [React's documentation](https://react.dev/reference/react).\n\nI recommend using PureScript's \"qualified do\" syntax whilst using this library (it's used in the examples, the `React.do` bits).\nIt became available in the `0.12.2` compiler release.\n\nThis library provides the `React.Basic.Hooks` module, which can completely replace the `React.Basic` module.\nIt 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.\nIf we prefer this API over the existing react-basic API, we may eventually replace `React.Basic` with this implementation.\n\n## React Version Support\n\n- **React 16.8+**: Core hooks (useState, useEffect, useReducer, useRef, useContext, useMemo, useDebugValue, useLayoutEffect)\n- **React 18+**: useId, useTransition, useDeferredValue, useSyncExternalStore, useInsertionEffect\n- **React 19+**: useOptimistic, useActionState, useEffectEvent (experimental)\n\n## Example\n\n```purs\nmkCounter :: Component Int\nmkCounter = do\n  component \"Counter\" \\initialValue -\u003e React.do\n    counter /\\ setCounter \u003c- useState initialValue\n\n    pure\n      $ R.button\n          { onClick: handler_ do\n              setCounter (_ + 1)\n          , children:\n              [ R.text $ \"Increment: \" \u003c\u003e show counter ]\n          }\n```\n\n## React 19 Hooks\n\n### useOptimistic\n\nOptimistically update the UI whilst waiting for an async action to complete. The optimistic state automatically reverts to the actual state when the action finishes.\n\n```purs\nmkMessageList :: Component Props\nmkMessageList = do\n  component \"MessageList\" \\{ messages } -\u003e React.do\n    optimisticMessages /\\ addOptimisticMessage \u003c- useOptimistic messages \\state newMessage -\u003e\n      Array.snoc state newMessage\n    \n    isPending /\\ startTransition \u003c- useTransition\n    \n    let handleSend message = startTransition do\n          addOptimisticMessage message\n          -- Async operation to send message to server\n          sendToServer message\n    \n    pure $ R.div_ (map renderMessage optimisticMessages)\n```\n\n### useActionState\n\nManage 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.\n\n```purs\nmkForm :: Component Unit\nmkForm = do\n  component \"Form\" \\_ -\u003e React.do\n    state /\\ (formAction /\\ isPending) \u003c- useActionState initialState updateFn\n      where\n        updateFn prevState formData = do\n          -- Process form submission (Effect version)\n          result \u003c- submitToServer formData\n          pure (Result.fromEither result)\n    \n    pure $ R.button\n      { disabled: isPending\n      , onClick: handler_ (formAction myFormData)\n      , children: [ R.text if isPending then \"Submitting...\" else \"Submit\" ]\n      }\n```\n\nFor progressive enhancement (form works without JavaScript), use `useActionStateWithPermalink`:\n\n```purs\nstate /\\ (formAction /\\ isPending) \u003c- useActionStateWithPermalink initialState updateFn \"/api/submit\"\n\npure $ R.form\n  { action: formAction  -- Falls back to /api/submit without JS\n  , children: [ ... ]\n  }\n```\n\n### useAffActionState\n\nAff version of `useActionState` for async operations. Available in `React.Basic.Hooks.Aff`. Uses Aff for natural async handling.\n\n```purs\nimport React.Basic.Hooks.Aff (useAffActionState)\n\nmkForm :: Component Unit\nmkForm = do\n  component \"Form\" \\_ -\u003e React.do\n    state /\\ (formAction /\\ isPending) \u003c- useAffActionState initialState affFn\n      where\n        affFn prevState formData = do\n          -- Process form submission (Aff version - natural async!)\n          result \u003c- Aff.submitToServer formData\n          pure (Result.fromEither result)\n    \n    pure $ R.button\n      { disabled: isPending\n      , onClick: handler_ (formAction myFormData)\n      , children: [ R.text if isPending then \"Submitting...\" else \"Submit\" ]\n      }\n```\n\nWith permalink: `useAffActionStateWithPermalink initialState affFn \"/api/submit\"`\n\n### useEffectEvent\n\nExtract 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.\n\n```purs\nmkComponent :: Component Props\nmkComponent = do\n  component \"Component\" \\{ url, onSuccess } -\u003e React.do\n    count /\\ setCount \u003c- useState 0\n    \n    -- onSuccess can use the latest count without re-running the effect\n    onSuccessEvent \u003c- useEffectEvent \\data -\u003e do\n      onSuccess data count\n    \n    -- Effect only re-runs when url changes, not when count changes\n    useEffect url do\n      response \u003c- fetchData url\n      onSuccessEvent response\n      pure mempty\n    \n    pure $ R.div_ [ ... ]\n```\n\n## Available Hooks\n\n### Core Hooks (React 16.8+)\n- `useState` / `useState'` — State management\n- `useEffect` / `useEffectOnce` / `useEffectAlways` — Side effects\n- `useLayoutEffect` — Synchronous layout effects\n- `useReducer` — State management with reducers\n- `useRef` — Mutable refs\n- `useContext` — Context consumption\n- `useMemo` — Memoised computation\n- `useDebugValue` — DevTools debugging labels\n\n### React 18 Hooks\n- `useId` — Unique ID generation\n- `useTransition` — Concurrent transitions\n- `useDeferredValue` — Deferred value updates\n- `useSyncExternalStore` — External store synchronisation\n- `useInsertionEffect` — DOM mutation effects\n\n### React 19 Hooks\n- `useOptimistic` — Optimistic UI updates\n- `useActionState` — Form action management\n- `useEffectEvent` — Non-reactive effect logic (experimental)\n\n### Additional Features\n- `memo` / `memo'` — Component memoisation\n- `component` — Component creation\n- Custom hooks via `React.Basic.Hooks.Aff` for async effects\n- `React.Basic.Hooks.Suspense` for Suspense support\n- `React.Basic.Hooks.ErrorBoundary` for error boundaries\n```\n","funding_links":[],"categories":["PureScript","UI"],"sub_categories":["React"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurescript-react%2Fpurescript-react-basic-hooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpurescript-react%2Fpurescript-react-basic-hooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurescript-react%2Fpurescript-react-basic-hooks/lists"}