Skip to content

Instantly share code, notes, and snippets.

@btoo
Created April 30, 2024 17:40
Show Gist options
  • Save btoo/2c56e0319de19e7c863a0cdd7ce04f99 to your computer and use it in GitHub Desktop.
Save btoo/2c56e0319de19e7c863a0cdd7ce04f99 to your computer and use it in GitHub Desktop.
effect-ts react component dependency injection demo
import { Context, Effect } from "effect";
import { jest } from '@jest/globals';
import React, { useEffect, useState } from "react";
interface Ad {
id: string
trackingEvent: string
}
export class FireTrackingEvent extends Context.Tag("FireTrackingEvent")<
FireTrackingEvent,
(url: string) => void
>() {}
export class FetchAd extends Context.Tag("FetchAd")<
FetchAd,
() => Promise<Ad | undefined>
>() {}
// NestedComponent.tsx
const generateNestedComponent = Effect.gen(function* () {
const fireTrackingEvent = yield* FireTrackingEvent
return function NestedComponent({ ad }: { ad: Ad }) {
return (
<button onClick={() => fireTrackingEvent(ad.trackingEvent)}>
Click me
</button>
)
}
})
// Component.tsx
const generateComponent = Effect.gen(function* () {
const NestedComponent = yield* generateNestedComponent
const fetchAd = yield* FetchAd
return function Component() {
const [ad, setAd] = useState<Ad>()
useEffect(() => {
fetchAd().then(setAd)
}, [])
return (
<div>
{ad ? <NestedComponent ad={ad} /> : null}
</div>
)
}
});
// LiveComponent.tsx
const LiveComponent = generateComponent.pipe(
Effect.provideService(FireTrackingEvent, fetch),
Effect.provideService(FetchAd, async () => ({ id: 'production ad', trackingEvent: 'https://www.example.com/production-tracking-event' })),
Effect.runSync
)
// Component.test.tsx
const TestComponent = generateComponent.pipe(
Effect.provideService(FireTrackingEvent, jest.fn()),
Effect.provideService(FetchAd, jest.fn<FetchAd['Type']>().mockResolvedValue({ id: 'test ad', trackingEvent: 'mock tracking event' })),
Effect.runSync
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment