Integration of React Router with Effect for React applications.
# npm
npm install @effectify/react-router
# yarn
yarn add @effectify/react-router
# pnpm
pnpm add @effectify/react-router
# bun
bun add @effectify/react-routerCreate a server runtime with your Effect layers:
// lib/server-runtime.ts
import { make } from "@effectify/react-router"
import * as Layer from "effect/Layer"
const layers = Layer.empty
export const { withLoaderEffect, withActionEffect } = make(layers)Use the Effect-based loaders and actions in your React Router routes:
// routes/home.tsx
import type * as Route from "./+types.home"
import { httpFailure, httpSuccess, LoaderArgsContext } from "@effectify/react-router"
import { withLoaderEffect } from "~/lib/server-runtime"
import * as Effect from "effect/Effect"
export const loader = withLoaderEffect(
Effect.gen(function*() {
const { request } = yield* LoaderArgsContext
yield* Effect.log("request", request)
// Improved DX: Simple syntax for success responses
return yield* httpSuccess({ hello: "world" })
// For error responses, use:
// return yield* httpFailure("Something went wrong")
}),
)
export default function Home({ loaderData }: Route.ComponentProps) {
return (
<div>
<h1>Home</h1>
<pre>{JSON.stringify(loaderData.data, null, 2)}</pre>
</div>
)
}The library provides helper functions for better DX when returning HTTP responses:
Instead of the verbose:
return yield * Effect.succeed(new HttpResponseSuccess({ data: { hello: "world" } }))Use the simplified syntax:
return yield * httpSuccess({ hello: "world" })For error handling, use the httpFailure helper:
return yield * httpFailure("Something went wrong")
// or with more complex error objects
return yield * httpFailure({ code: "VALIDATION_ERROR", message: "Invalid input" })For redirects, use the httpRedirect helper:
return yield * httpRedirect("/login")
// or with custom status/headers
return yield * httpRedirect("/dashboard", { status: 301 })Creates Effect-based runtime helpers for React Router.
layers: Effect Layer containing your application services and dependencies.
An object containing:
withLoaderEffect: Wrapper for React Router loaders using EffectwithActionEffect: Wrapper for React Router actions using Effect
Effect context providing access to React Router loader arguments including:
request: The incoming Request objectparams: Route parameterscontext: Additional context data
HttpResponseSuccess<T>(data): Successful HTTP response with dataHttpResponseFailure<T>(cause): Failed HTTP response with causeHttpResponseRedirect(to, init?): HTTP redirect response
httpSuccess<T>(data: T): Creates a successful Effect with HttpResponseSuccesshttpFailure<T>(cause: T): Creates a successful Effect with HttpResponseFailurehttpRedirect(to: string, init?: ResponseInit): Creates a successful Effect with HttpResponseRedirect
The library provides comprehensive error handling with full ErrorBoundary support:
- Automatic Error Logging: Errors are automatically logged using
Effect.logError - ErrorBoundary Compatible: Loader errors are properly thrown as
Responseobjects for React Router ErrorBoundary - Configurable Logging: Users can configure their own logging system through Effect layers
- Non-blocking: Logging doesn't block the main thread
- Structured Logging: Errors are logged with context and structured data
- Error Preservation: Original error context is preserved for better debugging
// The library automatically logs errors like this:
Effect.tapError((cause) => Effect.logError("Loader effect failed", cause))
// Loader errors are automatically converted to Response objects for ErrorBoundary:
// - Effect errors → Response with { ok: false, errors: [...] } and status 500
// - HttpResponseFailure → Response with { ok: false, errors: [...] } and status 500
// - Original Response/Error objects are preserved
// Users can configure custom logging through Effect layers
const customLogger = Logger.make(({ message, cause }) => {
// Custom logging implementation
console.log(`[${new Date().toISOString()}] ${message}`, cause)
})
const runtime = make(pipe(
// Your app layers
MyAppLayer,
// Custom logger layer
Logger.replace(Logger.defaultLogger, customLogger),
))- React Router v7+
- Effect ecosystem (
effect)
MIT