Skip to content

Commit 3bd0677

Browse files
committed
feat: new async fun & docs & examples
1 parent f10d2bb commit 3bd0677

File tree

11 files changed

+244
-180
lines changed

11 files changed

+244
-180
lines changed

README.md

Lines changed: 66 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,98 @@
11
# vue-subscription
22

3-
This is a TypeScript module for Vue.js, which provides a function `useSubscription` that returns an object with a shallow reactive value, a subscriber, and a few extra methods.
3+
This is a TypeScript module for Vue.js, which provides a function `useSubscription` that returns an object with a reactive value, a subscriber, and a few extra methods.
44

5-
The `useSubscription` function takes an initial value and returns an object with a reactive value property that is a shallowRef of the initial value passed in, and Subscriber functions can be added to a Set of subscribers to be executed when the value is changed.
5+
The `useSubscription` function takes an initial value and returns an object with a reactive value of the initial value passed in, and Subscriber functions can be added to a Set of subscribers to be executed when the value is changed.
66

7-
The module also includes methods to add, delete and trigger the subscribers as well as a method to mutate the value of the object. The `useSubscription` also returns an internal object named `$sub` with all the methods except readonly without the prefix `$`.
7+
The module also includes methods to add, delete and trigger the subscribers as well as a method to mutate the value if it is a more complex datatype(typeof object).
88

99
## Usage
1010

1111
```typescript
12+
const $mySubscription = useSubscription('hello'); // Type will be string
13+
14+
// Get the current value
15+
console.log($mySubscription.$value); // 'hello'
16+
1217
function mySubscriber(value: string) {
1318
console.log(`The value is now: ${value}`);
1419
}
1520

16-
function example() {
17-
const $mySubscription = useSubscription('hello');
21+
// Add a subscriber
22+
$mySubscription.$addSub(mySubscriber);
23+
// Manually trigger the subscribers if needed(rarely)
24+
$mySubscription.$triggerSubs(); // 'The value is now: hello'
1825

19-
// Get the current value
20-
console.log($mySubscription.value); // 'hello'
26+
// Set the value
27+
$mySubscription.$value = 'world';
2128

22-
// Add a subscriber
23-
$mySubscription.$subscriber = mySubscriber;
29+
// Subscriber runs here - 'The value is now: world'
2430

25-
// Set the value
26-
$mySubscription.value = 'world';
31+
// Remove a subscriber (can be used in Unmount, beforeRouteLeave etc)
32+
$mySubscription.$deleteSub(mySubscriber);
2733

28-
// Subscriber runs here - 'The value is now: world'
34+
// Use the readonly version of the value
35+
const myReadonlyValue = $mySubscription.$read;
36+
console.log(myReadonlyValue.value); // 'world'
37+
```
2938

30-
// Manually trigger the subscribers if needed(rarely)
31-
$mySubscription.$triggerSubs(); // 'The value is now: world'
39+
Example when using complex objects which won't be tracked deeply by default. Unless the subscriber is used in templates, watch, watchEffect and template you don't need to add the deep flag.
3240

33-
// Remove a subscriber (can be used in Unmount, beforeRouteLeave etc)
34-
$mySubscription.$deleteSub(mySubscriber);
41+
```typescript
42+
const $mySubscription = useSubscription(
43+
{
44+
user: {
45+
name: 'John',
46+
isActive: false
47+
}
48+
},
49+
// You can pass `true` as the deep flag to make the subscription deeply reactive if used in templates
50+
true
51+
);
52+
// Add a subscriber
53+
$mySubscription.$addSub(data => {
54+
console.log(`The data is now: ${JSON.stringify(data)}`);
55+
});
56+
57+
function myMutator(data: typeof $mySubscription.$value) {
58+
data.user.isActive = true;
59+
return data;
60+
}
61+
62+
// Trigger the subscribers
63+
$mySubscription.$triggerSubs(); // 'The data is now: { user: { name: 'John', isActive: false }}'
3564

36-
// Use the readonly version of the value
37-
const myReadonlyValue = $mySubscription.$ref;
38-
console.log(myReadonlyValue.value); // { name: 'world', age: 30 }
65+
function tester() {
66+
// Mutate the value (only works if the value is an object)
67+
$mySubscription.$mutate(myMutator);
68+
// Subscriber runs here - 'The data is now: { user: { name: 'John', isActive: true }}'
3969
}
70+
tester();
4071
```
4172

42-
Example when using complex objects which won't be tracked deeply by default
73+
You can also destructure the properties to have a seperate getter and setter.
4374

4475
```typescript
45-
function mySubscriber(data: object) {
46-
console.log(`The data is now: ${data}`);
47-
}
76+
const { $get, $set, $read, $addSub } = useSubscription('hello');
4877

49-
function myMutator(data: object) {
50-
data.isActive = true;
51-
return data;
52-
}
53-
54-
function example() {
55-
const $mySubscription = useSubscription({
56-
user: {
57-
name: Sravan,
58-
isActive: false
59-
}
60-
});
78+
// Get the current value
79+
console.log($get()); // 'hello'
6180

62-
// Get the current value
63-
console.log($mySubscription.value); // '{ user: { name: Sravan, isActive: false }}'
81+
function mySubscriber(value: string) {
82+
console.log(`The value is now: ${value}`);
83+
}
6484

65-
// Add a subscriber
66-
$mySubscription.$subscriber = mySubscriber;
85+
// Add a subscriber
86+
$addSub(mySubscriber);
6787

68-
// Trigger the subscribers
69-
$mySubscription.$triggerSubs(); // 'The data is now: { user: { name: Sravan, isActive: false }}'
88+
// Set the value
89+
$set('world');
7090

71-
// Mutate the value (only works if the value is an object)
72-
$mySubscription.$mutate(myMutator);
91+
// Subscriber runs here - 'The value is now: world'
7392

74-
// Subscriber runs here - 'The data is now: { user: { name: Sravan, isActive: true }}'
93+
$set(val => `Hello ${val}`);
94+
// Subscriber runs here - 'The value is now: Hello world'
7595

76-
console.log($mySubscription.value); // '{ user: { name: Sravan, isActive: true }}'
77-
}
96+
// Use the readonly version of the value
97+
console.log($read.value); // 'Hello world'
7898
```

demo/App.vue

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue';
3+
import ChildComp from './childComp.vue';
4+
import { useEventBus } from './composables/eventBus';
5+
6+
const testValue = ref(0);
7+
const eventBus = useEventBus();
8+
eventBus.$on((value) => {
9+
testValue.value = value;
10+
// ^?
11+
});
12+
</script>
13+
14+
<template>
15+
<div style="margin: 10rem">
16+
<h1>{{ testValue }}</h1>
17+
18+
<hr style="margin-top: 5rem; margin-bottom: 5rem" />
19+
<h1>{{ eventBus.$state.value }}</h1>
20+
<ChildComp />
21+
</div>
22+
</template>

demo/ChildComp.vue

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script setup lang="ts">
2+
import { useEventBus } from './composables/eventBus';
3+
4+
const eventBus = useEventBus();
5+
function incrementer() {
6+
eventBus.$emit(eventBus.$state.value + 1);
7+
}
8+
</script>
9+
10+
<template>
11+
<button style="margin: 5rem; padding: 2rem; border-radius: 50%" @click="incrementer()">Increase Count</button>
12+
</template>

demo/composables/eventBus.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { useSubscription } from '../../src/subscription';
2+
3+
const myEventBus = useSubscription(0);
4+
5+
export function useEventBus() {
6+
return {
7+
$on: myEventBus.$addSub,
8+
$off: myEventBus.$deleteSub,
9+
$emit: myEventBus.$set,
10+
$state: myEventBus.$read
11+
};
12+
}

demo/main.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { createApp } from 'vue';
2+
import App from '../demo/App.vue';
3+
4+
const app = createApp(App);
5+
6+
app.mount('#app');

index.html

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<!DOCTYPE html>
22
<html lang="en">
3-
<head>
4-
<meta charset="UTF-8">
5-
<link rel="icon" href="/favicon.ico">
6-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7-
<title>Vite App</title>
8-
</head>
9-
<body>
10-
<div id="app"></div>
11-
<script type="module" src="/src/main.ts"></script>
12-
</body>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" href="/favicon.ico" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Vite App</title>
8+
</head>
9+
<body>
10+
<div id="app"></div>
11+
<script type="module" src="/demo/main.ts"></script>
12+
</body>
1313
</html>

src/App.vue

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/functions/helpers.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,17 @@
55
* @param {T} arg - The argument to pass to the function.
66
* @returns A promise that resolves to the result of the function.
77
*/
8+
// eslint-disable-next-line @typescript-eslint/ban-types
89
export async function dynamicallyExecuteFunction<T>(func: Function, arg: T) {
9-
if (func.constructor.name === 'AsyncFunction') {
10-
return func(arg);
11-
}
12-
13-
return Promise.resolve(func(arg));
10+
try {
11+
const result = func(arg);
12+
if (result instanceof Promise) {
13+
return await result;
14+
} else {
15+
return result;
16+
}
17+
} catch (err) {
18+
// eslint-disable-next-line no-console
19+
console.error(err);
20+
}
1421
}

src/main.ts

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)