-
-
Notifications
You must be signed in to change notification settings - Fork 649
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* wip: atom with default util * chore: add tests (failing 😢 ) * atom with default with two atoms * add atomWithDefault docs * Add write to atomWithDefault * Update size snapshot * Revert "Add write to atomWithDefault" This reverts commit 3320848. * refactor in more idiomatic way without relying on undocumented behavior Co-authored-by: Thisen <[email protected]>
- Loading branch information
Showing
6 changed files
with
135 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { atom, PrimitiveAtom } from 'jotai' | ||
import type { Read } from '../core/types' | ||
|
||
export function atomWithDefault<Value>( | ||
getDefault: Read<Value> | ||
): PrimitiveAtom<Value> { | ||
const EMPTY = Symbol() | ||
const overwrittenAtom = atom<Value | typeof EMPTY>(EMPTY) | ||
const anAtom: PrimitiveAtom<Value> = atom( | ||
(get) => { | ||
const overwritten = get(overwrittenAtom) | ||
if (overwritten !== EMPTY) { | ||
return overwritten | ||
} | ||
return getDefault(get) | ||
}, | ||
(get, set, update) => | ||
set( | ||
overwrittenAtom, | ||
typeof update === 'function' | ||
? (update as (prev: Value) => Value)(get(anAtom)) | ||
: update | ||
) | ||
) | ||
return anAtom | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import React, { Fragment, Suspense } from 'react' | ||
import { fireEvent, render } from '@testing-library/react' | ||
import { Provider as ProviderOrig, atom, useAtom } from '../../src/index' | ||
import { atomWithDefault } from '../../src/utils' | ||
|
||
const Provider = process.env.PROVIDER_LESS_MODE ? Fragment : ProviderOrig | ||
|
||
it('simple sync get default', async () => { | ||
const count1Atom = atom(1) | ||
const count2Atom = atomWithDefault((get) => get(count1Atom) * 2) | ||
|
||
const Counter: React.FC = () => { | ||
const [count1, setCount1] = useAtom(count1Atom) | ||
const [count2, setCount2] = useAtom(count2Atom) | ||
return ( | ||
<> | ||
<div> | ||
count1: {count1}, count2: {count2} | ||
</div> | ||
<button onClick={() => setCount1((c) => c + 1)}>button1</button> | ||
<button onClick={() => setCount2((c) => c + 1)}>button2</button> | ||
</> | ||
) | ||
} | ||
|
||
const { findByText, getByText } = render( | ||
<Provider> | ||
<Counter /> | ||
</Provider> | ||
) | ||
|
||
await findByText('count1: 1, count2: 2') | ||
|
||
fireEvent.click(getByText('button1')) | ||
await findByText('count1: 2, count2: 4') | ||
|
||
fireEvent.click(getByText('button2')) | ||
await findByText('count1: 2, count2: 5') | ||
|
||
fireEvent.click(getByText('button1')) | ||
await findByText('count1: 3, count2: 5') | ||
}) | ||
|
||
it('simple async get default', async () => { | ||
const count1Atom = atom(1) | ||
const count2Atom = atomWithDefault(async (get) => { | ||
await new Promise((r) => setTimeout(r, 10)) | ||
return get(count1Atom) * 2 | ||
}) | ||
|
||
const Counter: React.FC = () => { | ||
const [count1, setCount1] = useAtom(count1Atom) | ||
const [count2, setCount2] = useAtom(count2Atom) | ||
return ( | ||
<> | ||
<div> | ||
count1: {count1}, count2: {count2} | ||
</div> | ||
<button onClick={() => setCount1((c) => c + 1)}>button1</button> | ||
<button onClick={() => setCount2((c) => c + 1)}>button2</button> | ||
</> | ||
) | ||
} | ||
|
||
const { findByText, getByText } = render( | ||
<Provider> | ||
<Suspense fallback="loading"> | ||
<Counter /> | ||
</Suspense> | ||
</Provider> | ||
) | ||
|
||
await findByText('loading') | ||
await findByText('count1: 1, count2: 2') | ||
|
||
fireEvent.click(getByText('button1')) | ||
await findByText('loading') | ||
await findByText('count1: 2, count2: 4') | ||
|
||
fireEvent.click(getByText('button2')) | ||
await findByText('count1: 2, count2: 5') | ||
|
||
fireEvent.click(getByText('button1')) | ||
await findByText('count1: 3, count2: 5') | ||
}) |