{"id":15413354,"url":"https://github.com/simonwep/reactivity-playground","last_synced_at":"2025-05-12T19:12:58.212Z","repository":{"id":66334248,"uuid":"507961677","full_name":"simonwep/reactivity-playground","owner":"simonwep","description":"💫 Simple recreation of reactivity as its mainly used in Vue3","archived":false,"fork":false,"pushed_at":"2022-07-03T09:48:04.000Z","size":55,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-12T19:12:44.757Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simonwep.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-06-27T15:22:06.000Z","updated_at":"2024-11-19T07:28:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"c95be490-94bc-441c-a3b5-e816e523de5e","html_url":"https://github.com/simonwep/reactivity-playground","commit_stats":{"total_commits":15,"total_committers":1,"mean_commits":15.0,"dds":0.0,"last_synced_commit":"ce0dc13e242463e430ed460de912725b1cf7d873"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonwep%2Freactivity-playground","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonwep%2Freactivity-playground/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonwep%2Freactivity-playground/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonwep%2Freactivity-playground/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simonwep","download_url":"https://codeload.github.com/simonwep/reactivity-playground/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253805852,"owners_count":21967053,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-01T16:56:44.199Z","updated_at":"2025-05-12T19:12:58.185Z","avatar_url":"https://github.com/simonwep.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Summary\n\n[![CI](https://github.com/Simonwep/reactivity-demo/actions/workflows/ci.yml/badge.svg)](https://github.com/Simonwep/reactivity-demo/actions/workflows/ci.yml)\n\nThis is a demo project to better understand how [Vue3's reactivity](https://vuejs.org/guide/extras/reactivity-in-depth.html#what-is-reactivity) works internally.\nSome features are ignored on purpose as it doesn't make that much sense to implement those in vanilla js without having a lifecycle.\n\n### Implementations\n\n* [Refs](#refs)\n* [Effects](#effects)\n* [Computed values](#computed-values)\n* [Watchers](#watchers)\n\n### Refs\n\n\u003e [back to top](#summary) | [source](src/lib/ref.ts) | [ref in vue](https://vuejs.org/api/reactivity-core.html#ref)\n\n#### Signature\n\n```ts\ntype Subscriber\u003cT = any\u003e = (newValue: T, oldValue: T) =\u003e void\n\ninterface Ref\u003cT = any\u003e {\n  subscribe(fn: Subscriber\u003cT\u003e);\n  unSubscribe(fn: Subscriber\u003cT\u003e);\n  value: T;\n};\n\ntype ref = (v: T) =\u003e Ref\u003cT\u003e;\n```\n\n#### Example\n\nA `ref` holds a single value which can be changed at any time and subscribed to:\n\n```ts\nconst a = ref(0);\n\na.subscribe((value, oldValue) =\u003e console.log({ value, oldValue }))\n\na.value = 5; // Logs {value: 5, oldValue: 0}\na.value = 2; // Logs {value: 2, oldValue: 5}\n```\n\n### Effects\n\n\u003e [back to top](#summary) | [source](src/lib/effect.ts) | [effects in vue](https://vuejs.org/api/reactivity-core.html#watcheffect)\n\n#### Signature\n\n````ts\ntype StopEffectCallback = () =\u003e void;\ntype effect = (fn: () =\u003e void) =\u003e StopEffectCallback;\n````\n\n#### Example\n\nAn effect takes a function which gets called whenever the ref accessed in it changes:\n\n```ts\nconst a = ref(0);\nconst b = ref(0);\n\neffect(() =\u003e console.log({ a: a.value, b: b.value }));\n\na.value = 5; // Logs {a: 5, b: 0}\nb.value = 3; // Logs {a: 5, b: 3}\n```\n\n`effect` returns a function to clear it:\n\n```ts\nconst a = ref(0);\nconst b = ref(0);\n\nconst stop = effect(() =\u003e console.log({ a: a.value, b: b.value }));\n\na.value = 5; // Logs {a: 5, b: 0}\n\nstop();\na.value = 5; // Logs nothing\n```\n\n### Computed values\n\n\u003e [back to top](#summary) | [source](src/lib/computed.ts) | [computed in vue](https://vuejs.org/guide/essentials/computed.html)\n\n#### Signature\n\n```ts\ntype ComputedRef\u003cT\u003e = ReadonlyRef\u003cT\u003e;\ntype computed = \u003cT\u003e(v: () =\u003e T) =\u003e ComputedRef\u003cT\u003e;\n```\n\n#### Example\n\nSame as effect but returning a value:\n\n```ts\nconst a = ref(0);\nconst b = ref(0);\n\nconst sum = computed(() =\u003e a.value + b.value);\n\nsum.subscribe((value, oldValue) =\u003e console.log({ value, oldValue }))\n\na.value = 3; // Logs {value: 3, oldValue: 0}\nb.value = 5; // Logs {value: 5, oldValue: 3}\n```\n\nTrying to set the value of a computed value will throw an error.\n\n### Watchers\n\n\u003e [back to top](#summary) | [source](src/lib/watch.ts) | [watchers in vue](https://vuejs.org/guide/essentials/watchers.html)\n\n#### Signature\n\n```ts\ninterface WatchOptions {\n  immediate?: boolean;\n};\n\ntype StopWatchCallback = () =\u003e void;\ntype WatchCallback\u003cT extends Ref[] | Ref\u003e = (args: UnwrapRefs\u003cT\u003e) =\u003e void;\n\ntype watch = \u003cT extends Ref[] | Ref\u003e(\n  refs: T,\n  cb: WatchCallback\u003cT\u003e,\n  options: WatchOptions\n) =\u003e StopWatchCallback;\n```\n\n#### Example\n\nWatches a list or a single ref.\n\n```ts\nconst a = ref(6);\nconst b = ref(3);\n\nconst stop = watch([a, b], ([a, b]) =\u003e {\n  console.log({ a, b }); // {a: 6, b: 4}\n});\n\n// Trigger watch by changing \"b\"\nb.value = 4;\n\n// Stop watching\nstop();\n```\n\n### Readonly\n\n\u003e [back to top](#summary) | [source](src/lib/readonly.ts) | [readonly in vue](https://vuejs.org/api/reactivity-core.html#readonly)\n\n#### Signature\n\n```ts\ntype ReadonlyRef\u003cT\u003e = Ref\u003cT\u003e;\ntype Readonly = \u003cT\u003e(v: Ref\u003cT\u003e) =\u003e ReadonlyRef\u003cT\u003e;\n```\n\n#### Example\n\nWraps a [`ref`](#refs) and marks it as readonly:\n\n```ts\nconst a = ref(6);\nconst b = readonly(a);\n\nb.value; // 6\na.value = 7;\n\nb.value; // 7;\nb.value = 5; // Throw error\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonwep%2Freactivity-playground","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimonwep%2Freactivity-playground","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonwep%2Freactivity-playground/lists"}