Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
{
"name": "@misaka17535/create-typed-event",
"version": "1.0.17",
"version": "1.0.18",
"description": "Function-based and directive tiny typed event, with current value and optional react hook. Proven and well-tested in private projects. 全功能、函数式调用的微型事件库,可读取当前值且带有可选 react hook。在内部项目中久经考验。",
"scripts": {
"build": "tsup",
"prepare:dist": "tsx ./scripts/copyRequiredFilesToDist.ts",
"test:link": "pnpm link ./dist",
"release": "tsx ./scripts/release.ts",
"postversion": "tsx ./scripts/copyRequiredFilesToDist.ts"
"release": "pnpm build && pnpm prepare:dist && np --contents=./dist --no-tests"
},
"main": "index.js",
"module": "index.mjs",
"types": "index.d.ts",
"exports": {
".": {
"types": "./index.d.ts",
"import": "./index.mjs",
"require": "./index.js",
"default": "./index.js"
},
"./react": {
"types": "./react.d.ts",
"import": "./react.mjs",
"require": "./react.js",
"default": "./react.js"
Expand All @@ -40,7 +42,7 @@
"publishConfig": {
"access": "public"
},
"packageManager": "pnpm",
"packageManager": "pnpm@9.0.0",
"devDependencies": {
"@types/lodash-es": "^4.17.12",
"@types/node": "^22.15.29",
Expand All @@ -55,10 +57,12 @@
"react": "^19.1.0",
"tsup": "^8.5.0",
"tsx": "^4.19.4",
"typescript": "^5.8.3"
"typescript": "^5.8.3",
"use-sync-external-store": "^1.6.0"
},
"peerDependencies": {
"react": ">=16"
"react": ">=16",
"use-sync-external-store": ">=1"
},
"peerDependenciesMeta": {
"react": {
Expand Down
33 changes: 20 additions & 13 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
packages:
- '.'

onlyBuiltDependencies:
- esbuild

Expand Down
10 changes: 0 additions & 10 deletions scripts/release.ts

This file was deleted.

9 changes: 5 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,12 @@ export const createTypedEvent = <T = void>({
cbs.map(v => v(payload));
},
once: (cb: cb<T>) => {
instance.sub((arg: T) => {
const wrappedCb = (arg: T) => {
cb(arg);
instance.unsub(cb);
});
return () => instance.unsub(cb);
instance.unsub(wrappedCb);
};
instance.sub(wrappedCb);
return () => instance.unsub(wrappedCb);
},
get value() {
return history[0];
Expand Down
31 changes: 23 additions & 8 deletions src/react.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {createTypedEvent, TypedEvent} from "./index";
import {Dispatch, SetStateAction, useCallback, useEffect, useMemo, useRef, useState} from "react";
import {Dispatch, SetStateAction, useCallback, useMemo, useRef, useState} from "react";
import {useSyncExternalStore} from "use-sync-external-store/shim";

const isFunction = (obj: any): obj is (...args: any) => any => {
return !!(obj && obj.constructor && obj.call && obj.apply);
const isFunction = (value: any): value is (...args: any) => any => {
return typeof value === "function";
};

// 临时直接嵌入 useHybridState 的实现,后续发包再改
Expand Down Expand Up @@ -62,9 +63,23 @@ export const createTypedEventMemorized: typeof createTypedEvent = (...args) =>
* const [marketPrice, setMarketPrice, marketPriceRef] = useTypedEventValue(marketPriceUpdateEvent);
*/
export const useTypedEventValue = <T = void>(event: TypedEvent<T>) => {
const [value, setValue, valueRef] = useHybridState<T>(event.value);
useEffect(() => {
return event.sub(setValue);
}, []);
return [value, event.dispatch, valueRef] as const;
const value = useSyncExternalStore(
useCallback((onStoreChange: () => void) => event.sub(() => onStoreChange()), [event]),
useCallback(() => event.value, [event]),
useCallback(() => event.value, [event]),
);
const valueRef = useRef(value);
valueRef.current = value;
const refBehindProxy = useMemo(
() =>
new Proxy(valueRef, {
set: () => {
throw new Error(
"Do not change value of this ref, it's readonly. Instead, use the set method.",
);
},
}),
[],
);
return [value, event.dispatch, refBehindProxy] as const;
};
7 changes: 7 additions & 0 deletions use-sync-external-store-shim.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
declare module "use-sync-external-store/shim" {
export function useSyncExternalStore<Snapshot>(
subscribe: (onStoreChange: () => void) => () => void,
getSnapshot: () => Snapshot,
getServerSnapshot?: () => Snapshot,
): Snapshot;
}