This commit is contained in:
@@ -370,7 +370,7 @@ that behavior, pass their tags with `Component.withOptions({ nonReactiveTags:
|
||||
|
||||
## Provide Services To A Subtree
|
||||
|
||||
Use `Component.useContextFromLayer` when an Effect View component should provide
|
||||
Use `Component.useLayer` when an Effect View component should provide
|
||||
extra services to another Effect View component. It turns a `Layer` into a runtime
|
||||
context that can be provided to `.use`.
|
||||
|
||||
@@ -381,19 +381,19 @@ import { GreetingView } from "./Greeting"
|
||||
import { GreetingLive } from "./services"
|
||||
|
||||
export const GreetingPageView = Component.make("GreetingPage")(function* () {
|
||||
const context = yield* Component.useContextFromLayer(GreetingLive)
|
||||
const context = yield* Component.useLayer(GreetingLive)
|
||||
const Greeting = yield* GreetingView.use.pipe(Effect.provide(context))
|
||||
|
||||
return <Greeting name="Effect" />
|
||||
})
|
||||
```
|
||||
|
||||
The layer passed to `useContextFromLayer` should be stable. If a new layer value
|
||||
The layer passed to `useLayer` should be stable. If a new layer value
|
||||
is created on every render, Effect View has to build a new context, which can
|
||||
cause unnecessary re-renders and scoped lifecycle restarts. Define static layers
|
||||
outside the component, or memoize layers that depend on React props or state.
|
||||
|
||||
Layers built with `useContextFromLayer` are scoped to the component that builds
|
||||
Layers built with `useLayer` are scoped to the component that builds
|
||||
them. That means service construction can register scoped logic, acquire
|
||||
resources, fork scoped fibers, and add finalizers that are tied to that
|
||||
component's lifecycle.
|
||||
|
||||
@@ -42,7 +42,7 @@ export class TodosView extends Component.make("TodosView")(function*() {
|
||||
}) {}
|
||||
|
||||
const Index = Component.make("IndexView")(function*() {
|
||||
const context = yield* Component.useContextFromLayer(TodosState.Default)
|
||||
const context = yield* Component.useLayer(TodosState.Default)
|
||||
const Todos = yield* Effect.provide(TodosView.use, context)
|
||||
|
||||
return <Todos />
|
||||
|
||||
@@ -1099,7 +1099,7 @@ export declare namespace useContext {
|
||||
* ```tsx
|
||||
* const MyLayer = Layer.succeed(MyService, new MyServiceImpl())
|
||||
* const MyComponent = Component.make(function*() {
|
||||
* const context = yield* Component.useContextFromLayer(MyLayer)
|
||||
* const context = yield* Component.useLayer(MyLayer)
|
||||
* const Sub = yield* SubComponent.use.pipe(
|
||||
* Effect.provide(context)
|
||||
* )
|
||||
@@ -1111,7 +1111,7 @@ export declare namespace useContext {
|
||||
* @example With memoized layer
|
||||
* ```tsx
|
||||
* const MyComponent = Component.make(function*(props: { id: string })) {
|
||||
* const context = yield* Component.useContextFromLayer(
|
||||
* const context = yield* Component.useLayer(
|
||||
* React.useMemo(() => Layer.succeed(MyService, new MyServiceImpl(props.id)), [props.id])
|
||||
* )
|
||||
* const Sub = yield* SubComponent.use.pipe(
|
||||
@@ -1126,17 +1126,15 @@ export declare namespace useContext {
|
||||
* ```tsx
|
||||
* const MyAsyncLayer = Layer.effect(MyService, someAsyncEffect)
|
||||
* const MyComponent = Component.make(function*() {
|
||||
* const context = yield* Component.useContextFromLayer(MyAsyncLayer)
|
||||
* const Sub = yield* SubComponent.use.pipe(
|
||||
* Effect.provide(context)
|
||||
* )
|
||||
* const context = yield* Component.useLayer(MyAsyncLayer)
|
||||
* const Sub = yield* Effect.provide(SubComponent, context)
|
||||
*
|
||||
* return <Sub />
|
||||
* }).pipe(
|
||||
* Async.async // Required to handle async layer effects
|
||||
* )
|
||||
*/
|
||||
export const useContextFromLayer = <ROut, E, RIn>(
|
||||
export const useLayer = <ROut, E, RIn>(
|
||||
layer: Layer.Layer<ROut, E, RIn>,
|
||||
options?: useContext.Options,
|
||||
): Effect.Effect<Context.Context<ROut>, E, RIn | Scope.Scope> => useOnChange(() => Effect.flatMap(
|
||||
|
||||
@@ -317,7 +317,7 @@ describe("Component", () => {
|
||||
() => Layer.succeed(ValueService, { value: props.value }),
|
||||
[props.value],
|
||||
)
|
||||
const context = yield* Component.useContextFromLayer(serviceLayer, {
|
||||
const context = yield* Component.useLayer(serviceLayer, {
|
||||
finalizerExecutionDebounce: 0,
|
||||
})
|
||||
const Child = yield* Effect.provide(SubComponent.use, context)
|
||||
|
||||
@@ -42,7 +42,7 @@ export class TodosView extends Component.make("TodosView")(function*() {
|
||||
}) {}
|
||||
|
||||
const Index = Component.make("IndexView")(function*() {
|
||||
const context = yield* Component.useContextFromLayer(TodosState.Default)
|
||||
const context = yield* Component.useLayer(TodosState.Default)
|
||||
const Todos = yield* Effect.provide(TodosView.use, context)
|
||||
|
||||
return <Todos />
|
||||
|
||||
@@ -1075,10 +1075,8 @@ export declare namespace useContext {
|
||||
* ```tsx
|
||||
* const MyLayer = Layer.succeed(MyService, new MyServiceImpl())
|
||||
* const MyComponent = Component.make(function*() {
|
||||
* const context = yield* Component.useContextFromLayer(MyLayer)
|
||||
* const Sub = yield* SubComponent.use.pipe(
|
||||
* Effect.provide(context)
|
||||
* )
|
||||
* const context = yield* Component.useLayer(MyLayer)
|
||||
* const Sub = yield* Effect.provide(SubComponent.use, context)
|
||||
*
|
||||
* return <Sub />
|
||||
* })
|
||||
@@ -1087,12 +1085,10 @@ export declare namespace useContext {
|
||||
* @example With memoized layer
|
||||
* ```tsx
|
||||
* const MyComponent = Component.make(function*(props: { id: string })) {
|
||||
* const context = yield* Component.useContextFromLayer(
|
||||
* const context = yield* Component.useLayer(
|
||||
* React.useMemo(() => Layer.succeed(MyService, new MyServiceImpl(props.id)), [props.id])
|
||||
* )
|
||||
* const Sub = yield* SubComponent.use.pipe(
|
||||
* Effect.provide(context)
|
||||
* )
|
||||
* const Sub = yield* Effect.provide(SubComponent.use, context)
|
||||
*
|
||||
* return <Sub />
|
||||
* })
|
||||
@@ -1102,17 +1098,15 @@ export declare namespace useContext {
|
||||
* ```tsx
|
||||
* const MyAsyncLayer = Layer.effect(MyService, someAsyncEffect)
|
||||
* const MyComponent = Component.make(function*() {
|
||||
* const context = yield* Component.useContextFromLayer(MyAsyncLayer)
|
||||
* const Sub = yield* SubComponent.use.pipe(
|
||||
* Effect.provide(context)
|
||||
* )
|
||||
* const context = yield* Component.useLayer(MyAsyncLayer)
|
||||
* const Sub = yield* Effect.provide(SubComponent.use, context)
|
||||
*
|
||||
* return <Sub />
|
||||
* }).pipe(
|
||||
* Async.async // Required to handle async layer effects
|
||||
* )
|
||||
*/
|
||||
export const useContextFromLayer = <ROut, E, RIn>(
|
||||
export const useLayer = <ROut, E, RIn>(
|
||||
layer: Layer.Layer<ROut, E, RIn>,
|
||||
options?: useContext.Options,
|
||||
): Effect.Effect<Context.Context<ROut>, E, RIn | Scope.Scope> => useOnChange(() => Effect.context<RIn>().pipe(
|
||||
|
||||
@@ -317,7 +317,7 @@ describe("Component", () => {
|
||||
() => Layer.succeed(ValueService, { value: props.value }),
|
||||
[props.value],
|
||||
)
|
||||
const context = yield* Component.useContextFromLayer(serviceLayer, {
|
||||
const context = yield* Component.useLayer(serviceLayer, {
|
||||
finalizerExecutionDebounce: 0,
|
||||
})
|
||||
const Child = yield* Effect.provide(SubComponent.use, context)
|
||||
|
||||
@@ -47,7 +47,7 @@ const LensFormPageView = Component.make("LensFormPageView")(function*() {
|
||||
yield* Console.log("LensForm route mounted")
|
||||
}))
|
||||
|
||||
const context = yield* Component.useContextFromLayer(AppState.layer)
|
||||
const context = yield* Component.useLayer(AppState.layer)
|
||||
const UserProfileEditor = yield* Effect.provide(UserProfileEditorView.use, context)
|
||||
|
||||
return <UserProfileEditor />
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"lint:tsc": "tsc --noEmit",
|
||||
"lint:tsc": "tsc -b --noEmit",
|
||||
"lint:biome": "biome lint",
|
||||
"preview": "vite preview",
|
||||
"clean:cache": "rm -rf .turbo node_modules/.tmp node_modules/.vite* .tanstack",
|
||||
|
||||
@@ -23,7 +23,7 @@ const SubComponent = Component.makeUntraced("SubComponent")(function*() {
|
||||
const ContextView = Component.makeUntraced("ContextView")(function*() {
|
||||
const [serviceValue, setServiceValue] = React.useState("test")
|
||||
const SubServiceLayer = React.useMemo(() => SubService.Default(serviceValue), [serviceValue])
|
||||
const SubComponentFC = yield* Effect.provide(SubComponent.use, yield* Component.useContextFromLayer(SubServiceLayer))
|
||||
const SubComponentFC = yield* Effect.provide(SubComponent.use, yield* Component.useLayer(SubServiceLayer))
|
||||
|
||||
return (
|
||||
<Container>
|
||||
|
||||
@@ -129,7 +129,7 @@ class RegisterFormView extends Component.make("RegisterFormView")(function*() {
|
||||
const RegisterPage = Component.make("RegisterPageView")(function*() {
|
||||
const RegisterForm = yield* Effect.provide(
|
||||
RegisterFormView.use,
|
||||
yield* Component.useContextFromLayer(RegisterFormService.Default),
|
||||
yield* Component.useLayer(RegisterFormService.Default),
|
||||
)
|
||||
|
||||
return <RegisterForm />
|
||||
|
||||
@@ -11,7 +11,7 @@ const TodosStateLive = TodosState.Default("todos")
|
||||
const Index = Component.make("IndexView")(function*() {
|
||||
const Todos = yield* Effect.provide(
|
||||
TodosView.use,
|
||||
yield* Component.useContextFromLayer(TodosStateLive),
|
||||
yield* Component.useLayer(TodosStateLive),
|
||||
)
|
||||
|
||||
return <Todos />
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true,
|
||||
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user