mirror of
https://github.com/re-rxjs/react-rxjs.git
synced 2025-12-08 18:01:51 +00:00
feat: use StateObservables as React elements (#280)
* override all * simplifyTypings * feat: improvements and tests to `stateJsx` Co-authored-by: Josep M Sobrepere <jm.sobrepere@gmail.com>
This commit is contained in:
parent
0c90ab717b
commit
59a8a2a5e5
@ -1,7 +1,7 @@
|
||||
import { Observable } from "rxjs"
|
||||
import { EMPTY_VALUE } from "../internal/empty-value"
|
||||
import { state, StateObservable, SUSPENSE } from "@rx-state/core"
|
||||
import { useStateObservable } from "../useStateObservable"
|
||||
import { useStateObservable } from "../"
|
||||
|
||||
/**
|
||||
* Accepts: A factory function that returns an Observable.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { EMPTY_VALUE } from "../internal/empty-value"
|
||||
import { Observable } from "rxjs"
|
||||
import { useStateObservable } from "../useStateObservable"
|
||||
import { useStateObservable } from "../"
|
||||
import { state } from "@rx-state/core"
|
||||
|
||||
/**
|
||||
|
||||
@ -1,5 +1,19 @@
|
||||
export * from "@rx-state/core"
|
||||
export { shareLatest } from "./shareLatest"
|
||||
export { useStateObservable } from "./useStateObservable"
|
||||
export {
|
||||
AddStopArg,
|
||||
DefaultedStateObservable,
|
||||
EmptyObservableError,
|
||||
liftSuspense,
|
||||
NoSubscribersError,
|
||||
PipeState,
|
||||
sinkSuspense,
|
||||
StateObservable,
|
||||
StatePromise,
|
||||
SUSPENSE,
|
||||
withDefault,
|
||||
WithDefaultOperator,
|
||||
} from "@rx-state/core"
|
||||
export { bind } from "./bind"
|
||||
export { Subscribe, RemoveSubscribe } from "./Subscribe"
|
||||
export { shareLatest } from "./shareLatest"
|
||||
export { state } from "./stateJsx"
|
||||
export { RemoveSubscribe, Subscribe } from "./Subscribe"
|
||||
export { useStateObservable } from "./useStateObservable"
|
||||
|
||||
47
packages/core/src/stateJsx.test.tsx
Normal file
47
packages/core/src/stateJsx.test.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { render, screen, act } from "@testing-library/react"
|
||||
import React, { Suspense } from "react"
|
||||
import { map, Subject } from "rxjs"
|
||||
import { state } from "./"
|
||||
|
||||
describe("stateJsx", () => {
|
||||
it("is possible to use StateObservables as JSX elements", async () => {
|
||||
const subject = new Subject<string>()
|
||||
const state$ = state(subject)
|
||||
const subscription = state$.subscribe()
|
||||
|
||||
render(<Suspense fallback="Waiting">{state$}</Suspense>)
|
||||
|
||||
expect(screen.queryByText("Result")).toBeNull()
|
||||
expect(screen.queryByText("Waiting")).not.toBeNull()
|
||||
|
||||
await act(() => {
|
||||
subject.next("Result")
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
expect(screen.queryByText("Result")).not.toBeNull()
|
||||
expect(screen.queryByText("Waiting")).toBeNull()
|
||||
subscription.unsubscribe()
|
||||
})
|
||||
|
||||
it("is possible to use factory StateObservables as JSX elements", async () => {
|
||||
const subject = new Subject<string>()
|
||||
const state$ = state((value: string) => subject.pipe(map((x) => value + x)))
|
||||
|
||||
const subscription = state$("hello ").subscribe()
|
||||
|
||||
render(<Suspense fallback="Waiting">{state$("hello ")}</Suspense>)
|
||||
|
||||
expect(screen.queryByText("hello world!")).toBeNull()
|
||||
expect(screen.queryByText("Waiting")).not.toBeNull()
|
||||
|
||||
await act(() => {
|
||||
subject.next("world!")
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
expect(screen.queryByText("hello world!")).not.toBeNull()
|
||||
expect(screen.queryByText("Waiting")).toBeNull()
|
||||
subscription.unsubscribe()
|
||||
})
|
||||
})
|
||||
27
packages/core/src/stateJsx.tsx
Normal file
27
packages/core/src/stateJsx.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { state as coreState, StateObservable } from "@rx-state/core"
|
||||
import React, { createElement, ReactElement } from "react"
|
||||
import { useStateObservable } from "./useStateObservable"
|
||||
|
||||
declare module "@rx-state/core" {
|
||||
interface StateObservable<T> extends ReactElement {}
|
||||
}
|
||||
|
||||
export const state: typeof coreState = (...args: any[]): any => {
|
||||
const result = (coreState as any)(...args)
|
||||
|
||||
if (typeof result === "function") {
|
||||
return (...args: any[]) => enhanceState(result(...args))
|
||||
}
|
||||
return enhanceState(result)
|
||||
}
|
||||
|
||||
const cache = new WeakMap<StateObservable<any>, React.ReactNode>()
|
||||
function enhanceState<T>(state$: StateObservable<T>) {
|
||||
if (!cache.has(state$))
|
||||
cache.set(
|
||||
state$,
|
||||
createElement(() => useStateObservable(state$) as any, {}),
|
||||
)
|
||||
|
||||
return Object.assign(state$, cache.get(state$)!)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user