Skip to content

Commit 0f52846

Browse files
committed
[ADD] useEvents hook + [FIX] various
1 parent 29aa868 commit 0f52846

19 files changed

Lines changed: 295 additions & 75 deletions

File tree

apps/react-tools-demo/scripts/generateMarkdown.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ ${lines.length > 0 ? lines.map(line => "> "+line).join("\n") : ""}
335335

336336
async function generateUtilsMarkDown() {
337337
const utilsFiles = await fs.readdir(path.join(pathUtilsDir));
338-
const indexFile = await fs.readFile(path.join(pathUtilsDir, "index.ts"), {encoding: "utf8"});
338+
const indexFile = await fs.readFile(path.join(pathUtilsDir, "..", "index.ts"), {encoding: "utf8"});
339339
for(let file of utilsFiles) {
340340
if(file !== "index.ts" && indexFile.includes(file.split(".ts")[0])) {
341341
let readedFile = await fs.readFile(path.join(pathUtilsDir, file), {encoding: "utf8"});
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { BaseSyntheticEvent, memo, useCallback, useEffect, useState } from "react";
2+
import { useEvents } from "../../../../../../packages/react-tools/src";
3+
4+
/**
5+
The component has:
6+
- A _useState_ that receives an object, with _value property.
7+
- A _useEvents_ that returns _addListener_ function.
8+
- A child component that has _useEvents_ that returns _dispatch_ function and renders an input text with an onChange handler that invoke the _dispatch_ function with a custom event with type _demo_ and with a custom event with input value as _detail_.
9+
10+
The main component calls _addlistener_ that updates component state inside an useEffect, in this way the listener _addListener_ is done only once and when the component is unmounted, it executes the _unlisten_.
11+
*/
12+
const ChildComponent = memo(() => {
13+
const [, dispatch] = useEvents();
14+
const onChange = useCallback((e: BaseSyntheticEvent) => {
15+
dispatch(new CustomEvent("demo", { detail: {value: e.target.value} }));
16+
}, [dispatch]);
17+
return (
18+
<input type="text" onChange={onChange} />
19+
);
20+
})
21+
const UseEvents = () => {
22+
const [state, setState] = useState({ value: "" });
23+
const [ addListener ] = useEvents();
24+
25+
useEffect(() => {
26+
const unsub = addListener("demo", (evt) => {
27+
setState((evt as CustomEvent).detail);
28+
})
29+
return () => {
30+
unsub();
31+
}
32+
}, [addListener]);
33+
34+
return <div>
35+
<p>Value is: {state.value}</p>
36+
<ChildComponent/>
37+
</div>
38+
}
39+
40+
UseEvents.displayName = "UseEvents";
41+
42+
export { UseEvents };

apps/react-tools-demo/src/components/hooks/usePubSubModel/UsePubSubModel.tsx renamed to apps/react-tools-demo/src/components/hooks/usePublishSubscribe/UsePublishSubscribe.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
import { BaseSyntheticEvent, memo, useCallback, useEffect, useState } from "react";
2-
import { usePubSubModel } from "../../../../../../packages/react-tools/src/hooks/usePubSubModel"
2+
import { usePublishSubscribe } from "../../../../../../packages/react-tools/src";
33

44
/**
55
The component has:
66
- A _useState_ that receives an object, with _value property.
7-
- A _usePubSubModel that receives __demo__ as topic and returns an object with _publish_ and _subscribe_ functions.
8-
- A child component that receives _publish function_ as prop and renders an input text with an onChange handler that invoke the publish function with input value as param.
7+
- A _usePubSubModel_ that receives __demo__ as topic and returns the _subscribe_ function.
8+
- A child component that use _usePubSubModel_ to get _publish_ function and renders an input text with an onChange handler that invoke the publish function with input value as param.
99
1010
The main component subscribe a listener, that updates component state, to the topic __demo__ inside an useEffect, in this way the listener _subscription_ is done only once and when the component is unmounted, it executes the _unsubscription_. The _subscription_ can be done outside useEffect also, what's important is that listener doesn't change when component rerenders (so it can be declared outside the component or with useCallback for example). In this case the _unsubscription_ is executed from hook.
1111
*/
12-
const ChildComponent = memo(({ publish }: { publish: (value: { value: string }) => Promise<void> }) => {
12+
const ChildComponent = memo(() => {
13+
const { publish } = usePublishSubscribe("demo");
1314
const onChange = useCallback((e: BaseSyntheticEvent) => {
1415
publish({ value: e.target.value })
1516
}, [publish]);
1617
return (
1718
<input type="text" onChange={onChange} />
1819
);
1920
})
20-
const UsePubSubModel = () => {
21+
const UsePublishSubscribe = () => {
2122
const [state, setState] = useState({ value: "" });
22-
const { publish, subscribe } = usePubSubModel<typeof state>("demo");
23+
const { subscribe } = usePublishSubscribe<typeof state>("demo");
2324

2425
useEffect(() => {
2526
const unsub = subscribe((obj?: { value: string }) => {
@@ -32,10 +33,10 @@ const UsePubSubModel = () => {
3233

3334
return <div>
3435
<p>Value is: {state.value}</p>
35-
<ChildComponent publish={publish}/>
36+
<ChildComponent/>
3637
</div>
3738
}
3839

39-
UsePubSubModel.displayName = "UsePubSubModel";
40+
UsePublishSubscribe.displayName = "UsePublishSubscribe";
4041

41-
export { UsePubSubModel };
42+
export { UsePublishSubscribe };

apps/react-tools-demo/src/constants/components.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ export const COMPONENTS = [
2121
"useEffectDeepCompare",
2222
"useLayoutEffectCompare",
2323
"useLayoutEffectDeepCompare",
24-
"usePubSubModel",
24+
"usePublishSubscribe",
25+
"useEvents",
2526
"useEventDispatcher",
2627
"useEventListener"
2728
],
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# isPlainObject
2+
Checks if `value` is a plain object, that is, an object created by the `Object` constructor or one with a `[[Prototype]]` of `null`.
3+
4+
## API
5+
6+
```tsx
7+
isPlainObject (value: any)
8+
```
9+
10+
> ### Params
11+
>
12+
> - __value__: _any_
13+
>
14+
15+
> ### Returns
16+
>
17+
> __result__
18+
> - _boolean_
19+
>

apps/react-tools-demo/src/markdown/useArray.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ const UseArray = () => {
1717
array.push(inputRef.current!.value);
1818
}, [array]);
1919

20-
const concat = useCallback(() => {
21-
array.concat(inputRef.current!.value);
22-
}, [array]);
23-
2420
return (<>
2521
{array.join(",")}
2622
<br />
@@ -29,7 +25,6 @@ const UseArray = () => {
2925
<div style={{ marginTop: 15, gridTemplateColumns: 'auto auto', justifyContent: 'center', display: 'grid', gap: '5px' }}>
3026
<button onClick={push}>Push</button>
3127
<button onClick={pop}>Pop</button>
32-
<button onClick={concat}>Concat</button>
3328
</div>
3429
</>);
3530
}
@@ -44,7 +39,6 @@ export { UseArray }
4439
> - An uncontrolled input with _inputRef_ ref used to execute buttons actions.
4540
> - A button _Push_ that push the input value into state by _push_ method of Array interface.
4641
> - A button _Pop_ that remove last item into state by _pop_ method of Array interface.
47-
> - A button _Concat_ that concats the input value with state by _concat_ method of Array interface.
4842
4943

5044
## API
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# useEvents
2+
Communication system based on Events pattern implemented on a EventTarget subclass. AddListener and dispatch functions to communicate. The result of invoking the _addListener_ function in turn returns a function that can be used to _removeListener_ on event. Otherwise, the listener is automatically removed when the component that has instantiated it is unmounted.
3+
4+
## Usage
5+
6+
```tsx
7+
const ChildComponent = memo(() => {
8+
const [, dispatch] = useEvents();
9+
const onChange = useCallback((e: BaseSyntheticEvent) => {
10+
dispatch(new CustomEvent("demo", { detail: e.target.value }));
11+
}, [dispatch]);
12+
return (
13+
<input type="text" onChange={onChange} />
14+
);
15+
})
16+
const UseEvents = () => {
17+
const [state, setState] = useState({ value: "" });
18+
const [ addListener ] = useEvents();
19+
20+
useEffect(() => {
21+
const unsub = addListener("demo", (evt) => {
22+
setState((evt as CustomEvent).detail);
23+
})
24+
return () => {
25+
unsub();
26+
}
27+
}, [addListener]);
28+
29+
return <div>
30+
<p>Value is: {state.value}</p>
31+
<ChildComponent/>
32+
</div>
33+
}
34+
35+
UseEvents.displayName = "UseEvents";
36+
37+
export { UseEvents };
38+
```
39+
40+
> The component has:
41+
> - A _useState_ that receives an object, with _value property.
42+
> - A _useEvents_ that returns _addListener_ function.
43+
> - A child component that has _useEvents_ that returns _dispatch_ function and renders an input text with an onChange handler that invoke the _dispatch_ function with a custom event with type _demo_ and with a custom event with input value as _detail_.
44+
>
45+
> The main component calls _addlistener_ that updates component state inside an useEffect, in this way the listener _addListener_ is done only once and when the component is unmounted, it executes the _unlisten_.
46+
47+
48+
## API
49+
50+
```tsx
51+
useEvents (): [(type: string, callback:<T>(evt: Event|CustomEvent<T>) => void, options?: boolean | AddEventListenerOptions) => ()=>void, <T>(evt: Event|CustomEvent<T>) => void]
52+
```
53+
54+
> ### Params
55+
>
56+
>
57+
>
58+
59+
> ### Returns
60+
>
61+
> __result__: contains the _addListener_ and _dispatch_ functions.
62+
> - __Union of__:
63+
> - __Array__:
64+
> - _(type: string, callback<T>:(evt: Even_
65+
> - _CustomEvent<T>) => void, options?: boolean_
66+
> - _AddEventListenerOptions) => ()=>void, <T>(evt: Event_
67+
> - _CustomEvent<T>) => void]_
68+
>

apps/react-tools-demo/src/markdown/usePubSubModel.md renamed to apps/react-tools-demo/src/markdown/usePublishSubscribe.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
# usePubSubModel
1+
# usePublishSubscribe
22
Communication system based on PubSub pattern. Instantiate a topic and use the publish and subscribe functions to communicate.
33

44
## Usage
55

66
```tsx
7-
const ChildComponent = memo(({ publish }: { publish: (value: { value: string }) => Promise<void> }) => {
7+
const ChildComponent = memo(() => {
8+
const { publish } = usePublishSubscribe("demo");
89
const onChange = useCallback((e: BaseSyntheticEvent) => {
910
publish({ value: e.target.value })
1011
}, [publish]);
1112
return (
1213
<input type="text" onChange={onChange} />
1314
);
1415
})
15-
const UsePubSubModel = () => {
16+
const UsePublishSubscribe = () => {
1617
const [state, setState] = useState({ value: "" });
17-
const { publish, subscribe } = usePubSubModel<typeof state>("demo");
18+
const { subscribe } = usePublishSubscribe<typeof state>("demo");
1819

1920
useEffect(() => {
2021
const unsub = subscribe((obj?: { value: string }) => {
@@ -27,27 +28,27 @@ const UsePubSubModel = () => {
2728

2829
return <div>
2930
<p>Value is: {state.value}</p>
30-
<ChildComponent publish={publish}/>
31+
<ChildComponent/>
3132
</div>
3233
}
3334

34-
UsePubSubModel.displayName = "UsePubSubModel";
35+
UsePublishSubscribe.displayName = "UsePublishSubscribe";
3536

36-
export { UsePubSubModel };
37+
export { UsePublishSubscribe };
3738
```
3839

3940
> The component has:
4041
> - A _useState_ that receives an object, with _value property.
41-
> - A _usePubSubModel that receives __demo__ as topic and returns an object with _publish_ and _subscribe_ functions.
42-
> - A child component that receives _publish function_ as prop and renders an input text with an onChange handler that invoke the publish function with input value as param.
42+
> - A _usePubSubModel_ that receives __demo__ as topic and returns the _subscribe_ function.
43+
> - A child component that use _usePubSubModel_ to get _publish_ function and renders an input text with an onChange handler that invoke the publish function with input value as param.
4344
>
4445
> The main component subscribe a listener, that updates component state, to the topic __demo__ inside an useEffect, in this way the listener _subscription_ is done only once and when the component is unmounted, it executes the _unsubscription_. The _subscription_ can be done outside useEffect also, what's important is that listener doesn't change when component rerenders (so it can be declared outside the component or with useCallback for example). In this case the _unsubscription_ is executed from hook.
4546
4647

4748
## API
4849

4950
```tsx
50-
usePubSubModel <T>(topic: string): { publish: (value?: T) => Promise<void>, subscribe: (listener: (value?: T) => Promise<void> | void) => () => void }
51+
usePublishSubscribe <T>(topic: string): { publish: (value?: T) => Promise<void>, subscribe: (listener: (value?: T) => Promise<void> | void) => () => void }
5152
```
5253

5354
> ### Params

apps/react-tools-demo/src/router/Router.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ import isMouseEventMD from '../markdown/isMouseEvent.md?url';
2626
import isTouchEventMD from '../markdown/isTouchEvent.md?url';
2727
import isClientMD from '../markdown/isClient.md?url';
2828
import isPlainObjectMD from '../markdown/isPlainObject.md?url';
29-
import usePubSubModelMD from '../markdown/usePubSubModel.md?url';
29+
import usePublishSubscribeMD from '../markdown/usePublishSubscribe.md?url';
30+
import useEventsMD from '../markdown/useEvents.md?url';
3031
import useEventDispatcherMD from '../markdown/useEventDispatcher.md?url';
3132
import useLocalStorageStateMD from '../markdown/useLocalStorageState.md?url';
3233
import useSessionStorageStateMD from '../markdown/useSessionStorageState.md?url';
@@ -42,7 +43,7 @@ import { UseMemoDeepCompare } from '../components/hooks/useMemoDeepCompare/UseMe
4243
import { UseEffectCompare } from '../components/hooks/useEffectCompare/UseEffectCompare';
4344
import { UseEffectDeepCompare } from '../components/hooks/useEffectDeepCompare/UseEffectDeepCompare';
4445
import { UseStateGetReset } from '../components/hooks/useStateGetReset/UseStateGetReset';
45-
import { UsePubSubModel } from '../components/hooks/usePubSubModel/UsePubSubModel';
46+
import { UsePublishSubscribe } from '../components/hooks/usePublishSubscribe/UsePublishSubscribe';
4647
import { UseMemoizedFunction } from '../components/hooks/useMemoizedFunction/UseMemoizedFunction';
4748
import { UseLocalStorageState } from '../components/hooks/useLocalStorageState/UseLocalStorageState';
4849
import { UseSessionStorageState } from '../components/hooks/useSessionStorageState/UseSessionStorageState';
@@ -51,6 +52,7 @@ import { UseEventDispatcher } from '../components/hooks/useEventDispatcher/UseEv
5152
import { UseMap } from '../components/hooks/useMap/UseMap';
5253
import { UseSet } from '../components/hooks/useSet/UseSet';
5354
import { UseArray } from '../components/hooks/useArray/UseArray';
55+
import { UseEvents } from '../components/hooks/useEvents/UseEvents';
5456

5557
function Router() {
5658
const router = createBrowserRouter([
@@ -204,10 +206,17 @@ function Router() {
204206
/>
205207
},
206208
{
207-
path: "/usePubSubModel",
209+
path: "/usePublishSubscribe",
208210
element: <ComponentLayout
209-
component={<UsePubSubModel />}
210-
markdown={usePubSubModelMD}
211+
component={<UsePublishSubscribe />}
212+
markdown={usePublishSubscribeMD}
213+
/>
214+
},
215+
{
216+
path: "/useEvents",
217+
element: <ComponentLayout
218+
component={<UseEvents/>}
219+
markdown={useEventsMD}
211220
/>
212221
},
213222
{

packages/react-tools/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
- [ ] useLongPress
5555
- [x] useEventDispatcher
5656
- [x] usePubSubModel
57+
- [x] useEvents
5758

5859
- __DOM API__
5960
- [ ] useCoptyToClipboard

0 commit comments

Comments
 (0)