diff --git a/docs/README.md b/docs/README.md index bea634937..2d7df38e4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,7 +6,6 @@ ![basics](https://user-images.githubusercontent.com/4677417/186188965-73453154-fdec-4d6b-9c34-cb35c248ae5b.png) - ## πŸš€ Project Structure Inside of your Astro project, you'll see the following folders and files: diff --git a/docs/src/content/docs/blog/what-is-state-manager.md b/docs/src/content/docs/blog/what-is-state-manager.md index 1821fc13a..66d993004 100644 --- a/docs/src/content/docs/blog/what-is-state-manager.md +++ b/docs/src/content/docs/blog/what-is-state-manager.md @@ -74,7 +74,7 @@ The last condition is very important - computational resources are limited, so w You can talk about the state as data related by some meaning, although often we are talking about some specific cache. For example, traffic light data contains information about three light bulbs, their colors and which one is on. Semantics follows from the subject area and represents the meaning of the data: only one light bulb can be turned on at a time, and the order of their switching is strictly regulated, this information is described not by the data structure, but by the code, therefore less explicit, although no less important. -The traffic light example deduced an important distinguishing feature of state as a phenomenon, is the need for data consistency: we cannot turn on one light without turning off the other, otherwise we would get erroneous data with their unpredictable impact on the user. The property of a state to be always consistent, i.e. to contain non-contradictory data, is called [atomicity](https://en.wikipedia.org/wiki/Atomicity_(database_systems)) in database theory. +The traffic light example deduced an important distinguishing feature of state as a phenomenon, is the need for data consistency: we cannot turn on one light without turning off the other, otherwise we would get erroneous data with their unpredictable impact on the user. The property of a state to be always consistent, i.e. to contain non-contradictory data, is called [atomicity]() in database theory. > [Here is the test of atomicity for a few state managers](https://github.com/artalar/state-management-specification/blob/master/src/index.test.js). Btw, React.js throws all your app away from screen if uncaught error occurs in render function, there is no way to get inconsistent state during render. diff --git a/docs/src/content/docs/compat/core-v1.md b/docs/src/content/docs/compat/core-v1.md index 79837c164..b2d13d51f 100644 --- a/docs/src/content/docs/compat/core-v1.md +++ b/docs/src/content/docs/compat/core-v1.md @@ -17,12 +17,8 @@ before import { declareAction, declareAtom, map, combine } from '@reatom/core-v1' const add = declareAction() -const n1Atom = declareAtom(0, (on) => [ - on(add, (state, value) => state + value), -]) -const n2Atom = declareAtom(0, (on) => [ - on(add, (state, value) => state + value), -]) +const n1Atom = declareAtom(0, (on) => [on(add, (state, value) => state + value)]) +const n2Atom = declareAtom(0, (on) => [on(add, (state, value) => state + value)]) const sumAtom = map(combine([n1Atom, n2Atom]), ([n1, n2]) => n1 + n2) const rootAtom = combine({ sumAtom }) ``` @@ -34,12 +30,8 @@ import { declareAction, declareAtom, combine, v3toV1 } from '@reatom/core-v1' import { atom } from '@reatom/core' const add = declareAction() -const n1Atom = declareAtom(0, (on) => [ - on(add, (state, value) => state + value), -]) -const n2Atom = declareAtom(0, (on) => [ - on(add, (state, value) => state + value), -]) +const n1Atom = declareAtom(0, (on) => [on(add, (state, value) => state + value)]) +const n2Atom = declareAtom(0, (on) => [on(add, (state, value) => state + value)]) const sumAtom = atom((ctx) => ctx.spy(n1Atom.v3atom) + ctx.spy(n2Atom.v3atom)) const rootAtom = combine({ sumAtom: v3toV1(sumAtom) }) ``` diff --git a/docs/src/content/docs/compat/core-v2.md b/docs/src/content/docs/compat/core-v2.md index 04ea0449e..86e9e83ed 100644 --- a/docs/src/content/docs/compat/core-v2.md +++ b/docs/src/content/docs/compat/core-v2.md @@ -206,13 +206,10 @@ import { createAtom } from '@reatom/core-v2' type TimerCtx = { intervalId?: number | NodeJS.Timer | any } /** Timer update interval */ -export const intervalAtom = createAtom( - { setSeconds: (seconds: number) => seconds }, - ({ onAction }, state = 1000) => { - onAction(`setSeconds`, (seconds) => (state = seconds * 1000)) - return state - }, -) +export const intervalAtom = createAtom({ setSeconds: (seconds: number) => seconds }, ({ onAction }, state = 1000) => { + onAction(`setSeconds`, (seconds) => (state = seconds * 1000)) + return state +}) export const timerAtom = createAtom( { @@ -239,10 +236,7 @@ export const timerAtom = createAtom( if (remains <= interval) { clearInterval(ctx.intervalId) - ctx.intervalId = setTimeout( - () => dispatch(create(`_update`, 0)), - remains, - ) + ctx.intervalId = setTimeout(() => dispatch(create(`_update`, 0)), remains) } dispatch(create(`_update`, remains)) @@ -318,10 +312,7 @@ But a better way is use the `createEnumAtom`. ```ts import { createEnumAtom } from '@reatom/core-v2/primitives' -const githubRepoSortFilterAtom = createEnumAtom( - ['full_name', 'created', 'updated', 'pushed'], - { format: 'snake_case' }, -) +const githubRepoSortFilterAtom = createEnumAtom(['full_name', 'created', 'updated', 'pushed'], { format: 'snake_case' }) console.log(sortFilterAtom.getState()) // -> 'full_name' @@ -462,11 +453,7 @@ const formAtom = createAtom( // you should't call `track.get` async // (scheduled callback calls async after all atoms) // (use `email` and `password` variables instead) - track.create( - '_fetch', - track.get('emailAtom'), - track.get('passwordAtom'), - ), + track.create('_fetch', track.get('emailAtom'), track.get('passwordAtom')), ), ) }) @@ -540,21 +527,18 @@ const counterAtom = createAtom({ inc: () => {} }, ({ onAction }, state = 0) => { Important note. Feel free to mutate **variable**, not a value. Reducer functions should not mutate any input values. ```ts -const counterAtom = createAtom( - { inc: () => {} }, - ({ onAction }, state = { count: 0 }) => { - // WRONG - onAction('inc', () => { - state.count++ - }) - // Right - onAction('inc', () => { - state = { count: state.count + 1 } - }) +const counterAtom = createAtom({ inc: () => {} }, ({ onAction }, state = { count: 0 }) => { + // WRONG + onAction('inc', () => { + state.count++ + }) + // Right + onAction('inc', () => { + state = { count: state.count + 1 } + }) - return state - }, -) + return state +}) ``` ### How to handle one action in a few atoms? diff --git a/docs/src/content/docs/compat/react-v1.md b/docs/src/content/docs/compat/react-v1.md index 8589e6cd0..da2e2f155 100644 --- a/docs/src/content/docs/compat/react-v1.md +++ b/docs/src/content/docs/compat/react-v1.md @@ -7,8 +7,6 @@ description: Reatom for react-v1 - - This is compatible package which allow you to use `@reatom/core-v1` with react. All docs is [here](/package/npm-react/). ## Setup batching for old React diff --git a/docs/src/content/docs/compat/react-v2.md b/docs/src/content/docs/compat/react-v2.md index 884c29557..c2d6d9385 100644 --- a/docs/src/content/docs/compat/react-v2.md +++ b/docs/src/content/docs/compat/react-v2.md @@ -62,10 +62,7 @@ const [data] = useAtom(dataAtom) #### Depended value by selector ```ts -const [propAtom] = useMemo( - () => createAtom({ dataAtom }, ({ get }) => get('dataAtom')[props.id]), - [props.id], -) +const [propAtom] = useMemo(() => createAtom({ dataAtom }, ({ get }) => get('dataAtom')[props.id]), [props.id]) const [propValue] = useAtom(propAtom) ``` @@ -82,10 +79,7 @@ const handleUpdateData = useAction(dataAtom.update) #### Prepare payload for dispatch ```ts -const handleUpdateData = useAction( - (value) => dataAtom.update({ id: props.id, value }), - [props.id], -) +const handleUpdateData = useAction((value) => dataAtom.update({ id: props.id, value }), [props.id]) ``` #### Conditional dispatch diff --git a/docs/src/content/docs/getting-started/learning.md b/docs/src/content/docs/getting-started/learning.md index 554dba34f..aa63d0e13 100644 --- a/docs/src/content/docs/getting-started/learning.md +++ b/docs/src/content/docs/getting-started/learning.md @@ -56,6 +56,8 @@ const cAtom = atom((ctx) => ctx.spy(aAtom) + ctx.spy(bAtom), 'cAtom') Computed atoms should be pure functions to ensure the correct order of all computations. +> Note: If a computed atom doesn't spy any other atoms, it will update whenever any atom in the context changes. + ### Read Atom To read the value of an atom, you need to use the previously created context. @@ -206,9 +208,7 @@ export const todoAtom = atom(null) export const isLoadingAtom = atom(false) export const fetchTodo = action(async (ctx) => { - const response = await ctx.schedule(() => - fetch('https://jsonplaceholder.typicode.com/todos/1'), - ) + const response = await ctx.schedule(() => fetch('https://jsonplaceholder.typicode.com/todos/1')) return await response.json() }) diff --git a/docs/src/content/docs/getting-started/setup.md b/docs/src/content/docs/getting-started/setup.md index bdd980a0c..bb18e386f 100644 --- a/docs/src/content/docs/getting-started/setup.md +++ b/docs/src/content/docs/getting-started/setup.md @@ -14,9 +14,10 @@ The base template project includes Vite, TypeScript, React and Reatom ecosystem. You can check in out [here](https://github.com/artalar/reatom-react-ts) You can also try it online: - - [codesandbox](https://codesandbox.io/p/sandbox/github/artalar/reatom-react-ts/tree/main) - - [stackblitz](https://githubblitz.com/artalar/reatom-react-ts) - - [gitpod](https://gitpod.io/#https://github.com/artalar/reatom-react-ts) + +- [codesandbox](https://codesandbox.io/p/sandbox/github/artalar/reatom-react-ts/tree/main) +- [stackblitz](https://githubblitz.com/artalar/reatom-react-ts) +- [gitpod](https://gitpod.io/#https://github.com/artalar/reatom-react-ts) To setup it in your machine you can use the [degit](https://github.com/Rich-Harris/degit) package. @@ -90,10 +91,7 @@ const nameAtom = atom('Joe') const Greeting = () => { const t = useTranslation() const [name, setName] = useAtom(nameAtom) - const [greeting] = useAtom( - (ctx) => `${t('common:GREETING')} ${ctx.spy(nameAtom)}!`, - [t], - ) + const [greeting] = useAtom((ctx) => `${t('common:GREETING')} ${ctx.spy(nameAtom)}!`, [t]) return ( <> diff --git a/docs/src/content/docs/getting-started/testing.md b/docs/src/content/docs/getting-started/testing.md index 23c258c07..8f5182813 100644 --- a/docs/src/content/docs/getting-started/testing.md +++ b/docs/src/content/docs/getting-started/testing.md @@ -57,18 +57,18 @@ In the next example, we have an async API. import { action, atom } from '@reatom/core' export const todoAtom = atom(null) -export const isLoadingAtom = atom(false); +export const isLoadingAtom = atom(false) export const fetchTodo = action(async (ctx) => { const response = await ctx.schedule(() => fetch('https://jsonplaceholder.typicode.com/todos/1')) - return await response.json(); + return await response.json() }) export const loadTodo = action(async (ctx) => { try { isLoadingAtom(ctx, true) const data = await ctx.schedule((ctx) => fetchTodo(ctx)) - todoAtom(ctx, data); + todoAtom(ctx, data) } catch (e) { console.error(e) } finally { @@ -80,13 +80,13 @@ export const loadTodo = action(async (ctx) => { Let's test it without calling the real api ```js -import { expect, test } from 'vitest'; -import { createTestCtx } from '@reatom/testing'; -import { loadTodo, fetchTodo, todoAtom } from './main'; +import { expect, test } from 'vitest' +import { createTestCtx } from '@reatom/testing' +import { loadTodo, fetchTodo, todoAtom } from './main' test('Test loadData atom', async () => { const ctx = createTestCtx() - const track = ctx.subscribeTrack(todoAtom) + const track = ctx.subscribeTrack(todoAtom) // Mock action with call ctx.mockAction(fetchTodo, (ctx) => Promise.resolve([{ id: 'foo' }])) diff --git a/docs/src/content/docs/index.md b/docs/src/content/docs/index.md index 088e0072e..53646aaef 100644 --- a/docs/src/content/docs/index.md +++ b/docs/src/content/docs/index.md @@ -28,7 +28,7 @@ description: Reatom - tiny and powerful reactive system with immutable nature - **smallest bundle** size: [2 KB](https://bundlejs.com/?q=%40reatom%2Fcore) gzipped With the power of base primitives, the whole ecosystem with A LOT of enterprise-level helpers takes only [~15KB](https://bundlejs.com/?q=%40reatom%2Fframework%2C%40reatom%2Fnpm-react%2C%40reatom%2Fpersist-web-storage%2C%40reatom%2Fundo%2C%40reatom%2Fform-web&config=%7B%22esbuild%22%3A%7B%22external%22%3A%5B%22react%22%2C%22use-sync-external-store%22%5D%7D%7D). Insane! - **the best TypeScript** experience - [Type inference](/recipes/typescript/) is one of the main priorities for Reatom. + [Type inference](/recipes/typescript/) is one of the main priorities for Reatom. [The core package](/core) includes most of these features and, due to its minimal overhead, can be used in any project, from small libraries to large applications. @@ -176,9 +176,7 @@ const fetchIssues = reatomAsync(async (ctx, query: string) => { withRetry({ onReject(ctx, error: any, retries) { // return delay in ms or -1 to prevent retries - return error?.message.includes('rate limit') - ? 100 * Math.min(500, retries ** 2) - : -1 + return error?.message.includes('rate limit') ? 100 * Math.min(500, retries ** 2) : -1 }, }), ) @@ -205,11 +203,7 @@ export const Search = () => { return (
- setSearch(e.currentTarget.value)} - placeholder="Search" - /> + setSearch(e.currentTarget.value)} placeholder="Search" /> {isLoading && 'Loading...'}