|
1 | | -# Custom Event Hook Library |
| 1 | +# @stainless-code/react-custom-events |
2 | 2 |
|
3 | 3 | This library provides utilities to simplify working with custom DOM events in React, allowing you to dispatch and listen for events in a declarative and type-safe manner. |
4 | 4 |
|
5 | | ---- |
6 | | - |
7 | 5 | ## Features |
8 | 6 |
|
9 | | -- **Type-safe custom event handling**: Define the payload type for your custom events. |
10 | | -- **Declarative React hooks**: Easily manage event listeners with React’s lifecycle. |
11 | | -- **Optional hooks customization**: Specify when to start/stop listening and include dependencies for event handling. |
12 | | - |
13 | | ---- |
| 7 | +- Typesafe |
| 8 | +- Reusable |
| 9 | +- Simple API |
| 10 | +- Centralised event dispatcher and listener |
14 | 11 |
|
15 | 12 | ## Installation |
16 | 13 |
|
17 | | -Install the library via npm or yarn: |
| 14 | +### npm |
18 | 15 |
|
19 | 16 | ```bash |
20 | | -# npm |
21 | | -npm i @stainless-code/react-custom-events |
22 | | - |
23 | | -# yarn |
24 | | -yarn add @stainless-code/react-custom-events |
25 | | - |
26 | | -# pnpm |
27 | | -pnpm add @stainless-code/react-custom-events |
28 | | - |
29 | | -# bun |
30 | | -bun add @stainless-code/react-custom-events |
| 17 | +npm install @stainless-code/react-custom-events |
31 | 18 | ``` |
32 | 19 |
|
33 | | ---- |
34 | | - |
35 | | -## API |
36 | | - |
37 | | -### `createCustomEvent<Payload>(eventName: string)` |
| 20 | +### yarn |
38 | 21 |
|
39 | | -Creates a custom event hook and dispatcher for a given event name. |
40 | | - |
41 | | -#### Parameters: |
42 | | - |
43 | | -- `eventName`: The name of the custom event to create. |
| 22 | +```bash |
| 23 | +yarn add @stainless-code/react-custom-events |
| 24 | +``` |
44 | 25 |
|
45 | | -#### Returns: |
| 26 | +### pnpm |
46 | 27 |
|
47 | | -A React hook with the following properties: |
| 28 | +```bash |
| 29 | +pnpm add @stainless-code/react-custom-events |
| 30 | +``` |
48 | 31 |
|
49 | | -- **Hook function**: A hook to listen for the custom event. |
50 | | -- **dispatch(payload, eventInitDict?)**: Dispatches the custom event with the given payload. |
| 32 | +### bun |
51 | 33 |
|
52 | | ---- |
| 34 | +```bash |
| 35 | +bun add @stainless-code/react-custom-events |
| 36 | +``` |
53 | 37 |
|
54 | | -### Hook: `useCustomEventListener<Payload>` |
| 38 | +## Usage |
55 | 39 |
|
56 | | -This hook listens for custom events and triggers a callback when the event occurs. |
| 40 | +### 1. Basic |
57 | 41 |
|
58 | | -#### Parameters: |
| 42 | +```tsx |
| 43 | +import { createCustomEvent } from "@stainless-code/react-custom-events"; |
59 | 44 |
|
60 | | -1. `eventName`: The name of the event to listen for. |
61 | | -2. `onListen(payload, event)`: Callback invoked with the event payload and the `CustomEvent` object. |
62 | | -3. `options?`: (Optional) Object containing: |
63 | | - - `listen`: A boolean to toggle event listening. |
64 | | - - `onStartListening`: A callback triggered when the hook starts listening. |
65 | | - - `onStopListening`: A callback triggered when the hook stops listening. |
66 | | -4. `deps?`: (Optional) Dependency list to control re-subscription. |
| 45 | +// Create event |
| 46 | +const useMyEvent = createCustomEvent<string>("my-event"); |
67 | 47 |
|
68 | | ---- |
| 48 | +function MyComponent() { |
| 49 | + // Listen for the event |
| 50 | + useMyEvent((payload) => console.log("Event received with payload:", payload)); |
69 | 51 |
|
70 | | -## Example Usage |
| 52 | + return ( |
| 53 | + // Dispatch event |
| 54 | + <button onClick={() => useMyEvent.dispatch("hello!")}> |
| 55 | + Dispatch event |
| 56 | + </button> |
| 57 | + ); |
| 58 | +} |
| 59 | +``` |
71 | 60 |
|
72 | | -### Creating a Custom Event |
| 61 | +### 2. With options and dependency list |
73 | 62 |
|
74 | | -```typescript |
| 63 | +```tsx |
75 | 64 | import { createCustomEvent } from "@stainless-code/react-custom-events"; |
| 65 | +import { useState } from "react"; |
| 66 | + |
| 67 | +// Create event |
| 68 | +const useMyEvent = createCustomEvent<string>("my-event"); |
| 69 | + |
| 70 | +function MyComponent() { |
| 71 | + const [enabled, setEnabled] = useState(true); |
| 72 | + |
| 73 | + // Listen for the event |
| 74 | + useMyEvent( |
| 75 | + (payload, event) => |
| 76 | + console.log("Event received with payload:", payload, event), |
| 77 | + { |
| 78 | + listen: enabled, // Control whether the listener is active |
| 79 | + onStartListening: () => console.log("Started listening"), |
| 80 | + onStopListening: () => console.log("Stopped listening"), |
| 81 | + }, |
| 82 | + [enabled], // Re-subscribe when `enabled` changes |
| 83 | + ); |
| 84 | + |
| 85 | + return ( |
| 86 | + <> |
| 87 | + <button onClick={() => setEnabled(!enabled)}> |
| 88 | + {enabled ? "Disable" : "Enable"} event listener |
| 89 | + </button> |
| 90 | + <button onClick={() => useMyEvent.dispatch("hello!")}> |
| 91 | + Dispatch event |
| 92 | + </button> |
| 93 | + </> |
| 94 | + ); |
| 95 | +} |
| 96 | +``` |
76 | 97 |
|
77 | | -// Define a custom event hook with a typed payload |
78 | | -const useMyEvent = createCustomEvent<{ age: number }>("myCustomEvent"); |
| 98 | +## Typesafety |
79 | 99 |
|
80 | | -// Dispatch the event |
81 | | -useMyEvent.dispatch({ age: 28 }); |
82 | | -``` |
| 100 | +```tsx |
| 101 | +const useMyEvent = createCustomEvent<string>("my-event"); |
83 | 102 |
|
84 | | -### Listening for Custom Events |
| 103 | +// dispatching |
| 104 | +useMyEvent.dispatch("Valid string payload"); // ✅ Correct type |
| 105 | +useMyEvent.dispatch(123); // ❌ TypeScript error: Expected 'string', got 'number' |
85 | 106 |
|
86 | | -```typescript |
87 | | -// Listen for the event |
| 107 | +// listening |
88 | 108 | useMyEvent((payload) => { |
89 | | - console.log(`Received age: ${payload.age}`); |
| 109 | + console.log(payload.toUpperCase()); // ✅ Correct method for string |
| 110 | + console.log(payload * 2); // ❌ TypeScript error: 'string' is not a number |
90 | 111 | }); |
91 | | - |
92 | | -// Advanced usage with options |
93 | | -useMyEvent( |
94 | | - (payload) => console.log(`Received age: ${payload.age}`), |
95 | | - { |
96 | | - listen: true, // Start listening immediately |
97 | | - onStartListening: () => console.log("Started listening"), |
98 | | - onStopListening: () => console.log("Stopped listening"), |
99 | | - }, |
100 | | - [ |
101 | | - /* dependencies */ |
102 | | - ], |
103 | | -); |
104 | 112 | ``` |
105 | 113 |
|
106 | | ---- |
107 | | - |
108 | | -## How It Works |
| 114 | +## API |
109 | 115 |
|
110 | | -1. **`createCustomEvent`**: |
| 116 | +### `createCustomEvent()` |
111 | 117 |
|
112 | | - - Creates a custom event dispatcher and corresponding hook for easy integration. |
113 | | - - The `dispatch` method triggers a DOM `CustomEvent` with the provided payload. |
| 118 | +Creates a custom event with a given name and returns a hook for listening to it and a `dispatch` function for triggering the event. |
114 | 119 |
|
115 | | -2. **`useCustomEventListener`**: |
116 | | - - Handles the lifecycle of adding and removing event listeners in a React-friendly manner. |
117 | | - - Automatically cleans up listeners when the component unmounts or dependencies change. |
| 120 | +| Parameter | Type | Description | Default | |
| 121 | +| ----------- | -------- | ----------------------------- | ---------- | |
| 122 | +| `eventName` | `string` | The name of the custom event. | (required) | |
118 | 123 |
|
119 | | ---- |
| 124 | +#### Returns |
120 | 125 |
|
121 | | -## Type Safety |
122 | | - |
123 | | -Leverage TypeScript to enforce strict type checking for your event payloads, ensuring reliability and reducing runtime errors. |
| 126 | +- `useCustomEventListener` with `eventName` prepopulated along with a `dispatch` method to trigger the event and the `eventName` property. |
124 | 127 |
|
125 | 128 | --- |
126 | 129 |
|
127 | | -## Example in Context |
128 | | - |
129 | | -```typescript |
130 | | -const useUserLoginEvent = createCustomEvent<{ userId: string }>("userLogin"); |
| 130 | +### `useCustomEventListener()` |
131 | 131 |
|
132 | | -// Dispatch the event |
133 | | -useUserLoginEvent.dispatch({ userId: "abc123" }); |
| 132 | +Custom hook to listen for a custom event and handle the payload. |
134 | 133 |
|
135 | | -// Listen for the event |
136 | | -useUserLoginEvent((payload) => |
137 | | - console.log(`User logged in: ${payload.userId}`), |
138 | | -); |
139 | | -``` |
140 | | - |
141 | | ---- |
| 134 | +| Parameter | Type | Description | Default | |
| 135 | +| -------------------------- | --------------------------------------------------------- | -------------------------------------------------------- | ------------------ | |
| 136 | +| `eventName` | `string` | The name of the custom event to listen for. | (required) | |
| 137 | +| `onListen` | `(payload: Payload, event: CustomEvent<Payload>) => void` | Callback to handle the event payload and event object. | (required) | |
| 138 | +| `options` (optional) | `Object` | Additional configuration for the event listener. | `{ listen: true }` | |
| 139 | +| `options.listen` | `boolean` | Whether the listener should be active (default: `true`). | `true` | |
| 140 | +| `options.onStartListening` | `() => void` | Callback when the listener starts. | `undefined` | |
| 141 | +| `options.onStopListening` | `() => void` | Callback when the listener stops. | `undefined` | |
| 142 | +| `deps` (optional) | `DependencyList` | Dependency list for re-subscribing to the event. | `undefined` | |
142 | 143 |
|
143 | 144 | ## Contributing |
144 | 145 |
|
145 | 146 | Feel free to submit issues or PRs to improve the library! |
146 | 147 |
|
147 | | ---- |
148 | | - |
149 | 148 | ## License |
150 | 149 |
|
151 | 150 | [MIT](./LICENSE) |
0 commit comments