UNPKG

rcrx

Version:

Rcrx is a lightweight library that provides Rx.js utilities for React applications.

278 lines (192 loc) 6.7 kB
# Rcrx Lightweight RxJS hooks for React. 简洁的 React + RxJS Hook 工具库。 - English | [中文](#中文说明) ## Overview Rcrx provides a minimal set of hooks to seamlessly use RxJS Observables within React components: - useObservable — read the latest value from an Observable as React state - useSubscribe — subscribe to an Observable and map each emission using your function Designed to be tiny, typed, and easy to adopt. ## Features - Minimal API, zero configuration - Automatic subscription management (unsubscribe on unmount) - TypeScript support with generics - Works with any RxJS Observable - Keeps subscription stable when the mapping function changes (via ref) ## Installation Using your favorite package manager: ```bash # pnpm pnpm add rcrx rxjs # npm npm install rcrx rxjs # yarn yarn add rcrx rxjs ``` Peer requirements: - react >= 16.8.0 (hooks) - rxjs (any 7+ recommended) ## Quick Start ### useObservable ```tsx import { useObservable } from "rcrx"; import { Observable } from "rxjs"; const counter$ = new Observable<number>((subscriber) => { let n = 0; const id = setInterval(() => subscriber.next(n++), 1000); return () => clearInterval(id); }); function Counter() { const n = useObservable(counter$); return <div>{n}</div>; } ``` ### useSubscribe ```tsx import { useSubscribe } from "rcrx"; import { Observable } from "rxjs"; import { useState } from "react"; const counter$ = new Observable<number>((subscriber) => { let n = 0; const id = setInterval(() => subscriber.next(n++), 1000); return () => clearInterval(id); }); function Counter() { const [n, setN] = useState(0); useSubscribe(counter$, (v) => setN(v)); return <div>{n}</div>; } ``` ## API ### useObservable<T>(observable: Observable<T>): T | undefined - Subscribes to the provided observable when the component mounts and returns the latest emitted value. - Re-subscribes if the observable instance changes. - Returns undefined until the first value is emitted. ### useSubscribe<TValue, TReturnValue>( observable: Observable<TValue>, fn: (value: TValue) => TReturnValue, defaultReturnValue?: TReturnValue ): TReturnValue | undefined - Subscribes to the observable and applies fn to each emission; the hook returns the latest mapped result. - Keeps the same subscription even if fn changes (fn is stored in a ref). - Re-subscribes if the observable instance changes. - Returns defaultReturnValue initially (or undefined if omitted). Notes: - For side-effects only, ignore the return value and use fn to update component state. - For derived state, return a mapped value from fn and read the hook's return value. ## Advanced Usage ### Switching Observables ```tsx function Dynamic({ source }: { source: Observable<number> }) { const value = useObservable(source); return <div>{value}</div>; } ``` When the source prop changes to a different Observable instance, the hook will unsubscribe from the previous one and subscribe to the new one. ### Mapping Without Re-subscribing ```tsx function Mapped({ source }: { source: Observable<number> }) { const doubled = useSubscribe(source, (v) => v * 2, 0); return <div>{doubled}</div>; } ``` Changing the mapping function identity won’t cause a re-subscription; only the Observable instance identity matters. ## TypeScript - Fully typed generics for both hooks - No additional TS configuration required ## Development - Build: `pnpm build` (outputs to `dist/` via tsup) - Test: `pnpm test` or `pnpm test:watch` (Vitest) ## License ISC --- # 中文说明 Rcrx 提供一组极简的 React + RxJS Hook,帮助你在 React 组件中无缝使用 RxJS Observable: - useObservable —— 将 Observable 的最新值作为组件状态读取 - useSubscribe —— 订阅 Observable,并用你的函数映射每次推送 ## 特性 - API 极简、开箱即用 - 自动管理订阅(组件卸载自动取消订阅) - 完整的 TypeScript 支持 - 适配任意 RxJS Observable - 当映射函数变更时保持订阅稳定(通过 ref## 安装 ```bash # pnpm pnpm add rcrx rxjs # npm npm install rcrx rxjs # yarn yarn add rcrx rxjs ``` 对等依赖与推荐: - react >= 16.8.0(支持 Hook) - rxjs(建议 7+) ## 快速上手 ### useObservable ```tsx import { useObservable } from "rcrx"; import { Observable } from "rxjs"; const counter$ = new Observable<number>((subscriber) => { let n = 0; const id = setInterval(() => subscriber.next(n++), 1000); return () => clearInterval(id); }); function Counter() { const n = useObservable(counter$); return <div>{n}</div>; } ``` ### useSubscribe ```tsx import { useSubscribe } from "rcrx"; import { Observable } from "rxjs"; import { useState } from "react"; const counter$ = new Observable<number>((subscriber) => { let n = 0; const id = setInterval(() => subscriber.next(n++), 1000); return () => clearInterval(id); }); function Counter() { const [n, setN] = useState(0); useSubscribe(counter$, (v) => setN(v)); return <div>{n}</div>; } ``` ## API 说明 ### useObservable<T>(observable: Observable<T>): T | undefined - 组件挂载时订阅 Observable,并返回其最新推送值;当 Observable 实例变化时自动重新订阅。 - 在首次推送之前返回 undefined。 ### useSubscribe<TValue, TReturnValue>( observable: Observable<TValue>, fn: (value: TValue) => TReturnValue, defaultReturnValue?: TReturnValue ): TReturnValue | undefined - 订阅 Observable,并对每次推送应用 fn;Hook 返回最近一次映射的结果。 - fn 变更不会触发重新订阅(内部通过 ref 保存最新 fn)。 - 当 Observable 实例变化时会重新订阅。 - 初始返回 defaultReturnValue(未传入则为 undefined)。 提示: - 仅用于副作用时,可忽略返回值,直接在 fn 中 setState。 - 需要派生状态时,可在 fn 中返回映射值,并通过 Hook 的返回值读取。 ## 进阶用法 ### 切换 Observable ```tsx function Dynamic({ source }: { source: Observable<number> }) { const value = useObservable(source); return <div>{value}</div>; } ``` 当 source 属性切换为新的 Observable 实例时,Hook 会自动取消之前的订阅,并订阅到新的实例。 ### 映射但不重新订阅 ```tsx function Mapped({ source }: { source: Observable<number> }) { const doubled = useSubscribe(source, (v) => v * 2, 0); return <div>{doubled}</div>; } ``` 映射函数的引用发生变化不会触发重新订阅;只有 Observable 实例变化时才会。 ## 本地开发 - 构建:`pnpm build`(使用 tsup 输出到 `dist/`) - 测试:`pnpm test` 或 `pnpm test:watch`(Vitest) ## 许可证 MIT