mirror of
https://github.com/re-rxjs/react-rxjs.git
synced 2025-12-08 18:01:51 +00:00
feat(core/useObservable): switch state when changing source
This commit is contained in:
parent
90e6a00920
commit
a37c1ca8db
@ -17,6 +17,7 @@ import {
|
||||
fireEvent,
|
||||
screen,
|
||||
render,
|
||||
act,
|
||||
} from "@testing-library/react"
|
||||
import { bind, Subscribe } from "../"
|
||||
import { TestErrorBoundary } from "../test-helpers/TestErrorBoundary"
|
||||
@ -183,6 +184,30 @@ describe("connectFactoryObservable", () => {
|
||||
subs.unsubscribe()
|
||||
})
|
||||
|
||||
it("immediately switches the state to the new observable", () => {
|
||||
const [useNumber, getNumber$] = bind((x: number) => of(x))
|
||||
const subs = merge(
|
||||
getNumber$(0),
|
||||
getNumber$(1),
|
||||
getNumber$(2),
|
||||
).subscribe()
|
||||
|
||||
const Form = ({ id }: { id: number }) => {
|
||||
const value = useNumber(id)
|
||||
|
||||
return <input role="input" key={id} defaultValue={value} />
|
||||
}
|
||||
|
||||
const { rerender, getByRole } = render(<Form id={0} />)
|
||||
expect((getByRole("input") as HTMLInputElement).value).toBe("0")
|
||||
|
||||
act(() => rerender(<Form id={1} />))
|
||||
expect((getByRole("input") as HTMLInputElement).value).toBe("1")
|
||||
|
||||
act(() => rerender(<Form id={2} />))
|
||||
expect((getByRole("input") as HTMLInputElement).value).toBe("2")
|
||||
})
|
||||
|
||||
it("handles optional args correctly", () => {
|
||||
const [, getNumber$] = bind((x: number, y?: number) => of(x + (y ?? 0)))
|
||||
|
||||
|
||||
@ -8,8 +8,15 @@ export const useObservable = <O>(
|
||||
keys: Array<any>,
|
||||
defaultValue: O,
|
||||
): Exclude<O, typeof SUSPENSE> => {
|
||||
const [state, setState] = useState(source$.gV)
|
||||
const prevStateRef = useRef<O | (() => O)>(state)
|
||||
const [state, setState] = useState<[O, any[]]>(() => [source$.gV(), keys])
|
||||
const prevStateRef = useRef<O | (() => O)>(state[0])
|
||||
|
||||
if (
|
||||
keys.length !== state[1].length ||
|
||||
keys.some((k, i) => state[1][i] !== k)
|
||||
) {
|
||||
setState([source$.gV(), keys])
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const { gV } = source$
|
||||
@ -29,8 +36,14 @@ export const useObservable = <O>(
|
||||
if (err !== EMPTY_VALUE) return
|
||||
|
||||
const set = (value: O | (() => O)) => {
|
||||
if (!Object.is(prevStateRef.current, value))
|
||||
setState((prevStateRef.current = value))
|
||||
if (!Object.is(prevStateRef.current, value)) {
|
||||
prevStateRef.current = value
|
||||
if (typeof value === "function") {
|
||||
setState(() => [(value as any)(), keys])
|
||||
} else {
|
||||
setState([value, keys])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (syncVal === EMPTY_VALUE) {
|
||||
@ -48,5 +61,5 @@ export const useObservable = <O>(
|
||||
}
|
||||
}, keys)
|
||||
|
||||
return state as Exclude<O, typeof SUSPENSE>
|
||||
return state[0] as Exclude<O, typeof SUSPENSE>
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user