Skip to content

Refactor Firestore CRUD to use Effect atoms and React hooks#45

Draft
fwal wants to merge 2 commits into
nextfrom
claude/react-library-patterns-T2Uia
Draft

Refactor Firestore CRUD to use Effect atoms and React hooks#45
fwal wants to merge 2 commits into
nextfrom
claude/react-library-patterns-T2Uia

Conversation

@fwal
Copy link
Copy Markdown
Owner

@fwal fwal commented May 22, 2026

Summary

Refactored the Firestore CRUD example to use @effect/atom-react for state management and reactive data fetching, replacing manual Effect/Stream management with declarative atom-based patterns. This demonstrates production-ready patterns for integrating Effect-TS repositories with React.

Key Changes

  • Atom-based architecture: Introduced atoms.ts with repository atoms for reads (latestPostsAtom, postByIdAtom) and mutations (addPostAtom, updatePostAtom, deletePostAtom), enabling shared subscriptions and automatic cleanup.

  • Runtime setup: Created a firestoreLayerAtom indirection layer that makes the Firestore service swappable at the registry boundary, enabling seamless testing with mock layers without changing component code.

  • Component refactoring:

    • Extracted PostForm component using @tanstack/react-form with Effect Schema validation
    • Extracted PostList component using AsyncResult.builder for exhaustive state handling
    • Simplified RouteComponent to coordinate form and list state
    • Removed manual Effect/Stream subscription management and fiber cleanup
  • App-level integration: Wrapped the app in RegistryProvider with memoized layer initialization to ensure stable runtime identity across renders.

  • Testing support: Added MockFirestoreService integration and example test demonstrating how to override the layer atom for unit tests without modifying components.

  • Documentation: Added comprehensive REACT.md guide covering runtime setup, repository atoms, reading data, mutations, form validation, and testing patterns.

Notable Implementation Details

  • Atom families (Atom.family) memoize atoms by argument, ensuring multiple components subscribed to the same resource share a single Firestore subscription.
  • clientRuntime.atom(effect) and clientRuntime.atom(stream) automatically wrap results in AsyncResult<A, E> for consistent loading/success/failure handling.
  • useAtomSet(atom, { mode: 'promise' }) enables fire-and-forget or promise-based mutations with automatic state tracking.
  • Form re-keying on editing?.id ensures fresh defaults load when switching between create and edit modes.
  • Subscriptions are refcounted with configurable TTL, allowing cached values to render immediately on re-mount within the idle window.

https://claude.ai/code/session_01R1D97BwwWVdGzARJY8iWeB

claude added 2 commits May 22, 2026 12:00
Introduce REACT.md and reference implementation in example/app for
using effect-firebase repositories from React: a RuntimeProvider that
binds a Firestore Layer to a ManagedRuntime, plus useEffectQuery,
useEffectStream, and useEffectMutation hooks that surface a Result-
shaped state and handle fiber cleanup. Refactor the /firestore route
to use the hooks together with @tanstack/react-form and effect/Schema
(via toStandardSchemaV1) for validated CRUD. Add a Vitest setup with
@testing-library/react and a demo test that swaps in
@effect-firebase/mock at the provider boundary.

The hook surface intentionally mirrors @effect-atom/atom-react idioms
so a future migration is mechanical once atom-react supports Effect
v4. Also remove a duplicate deleteRecursive key in the mock service
that blocked the package build.

https://claude.ai/code/session_01R1D97BwwWVdGzARJY8iWeB
Replace the hand-rolled RuntimeProvider + useEffectQuery/Stream/Mutation
hooks with the upstream Effect-TS React binding now that
@effect/atom-react has shipped for Effect v4.

Repository operations live in example/app/src/lib/atoms.ts as atoms
keyed by a swappable firestoreLayerAtom: postByIdAtom, postByIdLiveAtom,
latestPostsAtom, and addPost/updatePost/deletePostAtom mutations. The
firestore route reads via useAtomValue + AsyncResult.builder and writes
via useAtomSet({ mode: 'promise' }). RegistryProvider replaces the
custom provider; tests swap the layer via initialValues. REACT.md is
rewritten to document the atom-based patterns.

https://claude.ai/code/session_01R1D97BwwWVdGzARJY8iWeB
@nx-cloud
Copy link
Copy Markdown
Contributor

nx-cloud Bot commented May 22, 2026

View your CI Pipeline Execution ↗ for commit 30d85ef

Command Status Duration Result
nx affected -t lint test build ✅ Succeeded 59s View ↗

☁️ Nx Cloud last updated this comment at 2026-05-22 12:52:16 UTC

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0dd01139-2ccd-4787-948c-cb919ede1242

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@fwal fwal added this to the 1.0 - Effect v4 milestone May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants