@@ -1,47 +1,52 @@
|
|||||||
import { Context, Effect, Layer } from "effect"
|
import { Context, Effect, Layer, Runtime } from "effect"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
import * as ReffuseRuntime from "./ReffuseRuntime.js"
|
||||||
|
|
||||||
|
|
||||||
export interface ReffuseContext<R> {
|
export class ReffuseContext<R> {
|
||||||
readonly Context: React.Context<Context.Context<R>>
|
|
||||||
|
readonly Context = React.createContext<Context.Context<R>>(null!)
|
||||||
readonly Provider: ReffuseContextReactProvider<R>
|
readonly Provider: ReffuseContextReactProvider<R>
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.Provider = (props) => {
|
||||||
|
const runtime = ReffuseRuntime.use()
|
||||||
|
|
||||||
|
const value = React.useMemo(() => Effect.context<R>().pipe(
|
||||||
|
Effect.provide(props.layer),
|
||||||
|
Runtime.runSync(runtime),
|
||||||
|
), [runtime, props.layer])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<this.Context
|
||||||
|
{...props}
|
||||||
|
value={value}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
this.Provider.displayName = "ReffuseContextReactProvider"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
use(): Context.Context<R> {
|
||||||
|
return React.useContext(this.Context)
|
||||||
|
}
|
||||||
|
|
||||||
|
useLayer(): Layer.Layer<R> {
|
||||||
|
const context = this.use()
|
||||||
|
return React.useMemo(() => Layer.effectContext(Effect.succeed(context)), [context])
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ReffuseContextReactProvider<R> = React.FC<{
|
export type ReffuseContextReactProvider<R> = React.FC<{
|
||||||
readonly layer: Layer.Layer<R, unknown, never>
|
readonly layer: Layer.Layer<R, unknown>
|
||||||
readonly children?: React.ReactNode
|
readonly children?: React.ReactNode
|
||||||
}>
|
}>
|
||||||
|
|
||||||
export type R<T> = T extends ReffuseContext<infer R> ? R : never
|
export type R<T> = T extends ReffuseContext<infer R> ? R : never
|
||||||
|
|
||||||
|
|
||||||
export function make<R>(): ReffuseContext<R> {
|
export function make<R = never>() {
|
||||||
const Context = React.createContext<Context.Context<R>>(null!)
|
return new ReffuseContext<R>()
|
||||||
|
|
||||||
return {
|
|
||||||
Context,
|
|
||||||
|
|
||||||
Provider: function ReffuseContextReactProvider(props) {
|
|
||||||
return (
|
|
||||||
<Context
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
declare const MyService1: ReturnType<typeof Context.GenericTag<"MyService1", { readonly myService1: true }>>
|
|
||||||
declare const MyService2: ReturnType<typeof Context.GenericTag<"MyService2", { readonly myService2: true }>>
|
|
||||||
|
|
||||||
declare const Context1: Context.Context<typeof MyService1>
|
|
||||||
declare const Context2: Context.Context<typeof MyService2>
|
|
||||||
|
|
||||||
declare const MyService3: ReturnType<typeof Context.GenericTag<"MyService3", { readonly myService3: true }>>
|
|
||||||
declare const MyService3Live: Layer.Layer<typeof MyService3, never, typeof MyService1>
|
|
||||||
|
|
||||||
|
|
||||||
const res = MyService3Live.pipe(
|
|
||||||
Layer.provide(Layer.effectContext(Effect.succeed(Context1)))
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
import type { Runtime } from "effect"
|
|
||||||
import React from "react"
|
|
||||||
|
|
||||||
|
|
||||||
export interface ReffuseRuntime<R> extends React.Context<Runtime.Runtime<R>> {}
|
|
||||||
15
packages/reffuse/src/ReffuseRuntime.tsx
Normal file
15
packages/reffuse/src/ReffuseRuntime.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { Runtime } from "effect"
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
|
||||||
|
export const Context = React.createContext<Runtime.Runtime<never>>(null!)
|
||||||
|
|
||||||
|
export const Provider = (props: { readonly children?: React.ReactNode }) => (
|
||||||
|
<Context
|
||||||
|
{...props}
|
||||||
|
value={Runtime.defaultRuntime}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
Provider.displayName = "ReffuseRuntimeReactProvider"
|
||||||
|
|
||||||
|
export const use = () => React.useContext(Context)
|
||||||
Reference in New Issue
Block a user