diff --git a/docs/guides/debugging.mdx b/docs/guides/debugging.mdx index 79f8feb0e4..1e3fa6798e 100644 --- a/docs/guides/debugging.mdx +++ b/docs/guides/debugging.mdx @@ -135,8 +135,9 @@ Which returns atoms value that is deeply freezed with `Object.freeze`. freezeAtom(anAtom): AtomType ``` -`freezeAtom` takes an existing atom and returns a new derived "frozen" atom. -The atom will be deeply frozen by `Object.freeze`. +`freezeAtom` takes an existing atom and make it "frozen". +It returns the same atom. +The atom value will be deeply frozen by `Object.freeze`. It is useful to find bugs where you unintentionally tried to change objects (states) which can lead to unexpected behavior. You may use `freezeAtom` with all atoms to prevent this situation. @@ -156,14 +157,14 @@ const objAtom = freezeAtom(atom({ count: 0 })) ### freezeAtomCreator -```js -import { atom } from 'jotai' -import { freezeAtomCreator } from 'jotai/utils' +If you need, you can define a factory for `freezeAtom`. -const createFrozenAtom = freezeAtomCreator(atom) -const objAtom = createFrozenAtom({ count: 0 }) -``` +```ts +import { freezeAtom } from 'jotai/utils' -Instead of create a frozen atom from an existing atom, -`freezeAtomCreator` takes an atom creator function and returns a new function. -You can use this not only for `atom`, but also for other `atomWith*` creators such as `atomWithReduer`. +export function freezeAtomCreator< + CreateAtom extends (...args: unknown[]) => Atom, +>(createAtom: CreateAtom): CreateAtom { + return ((...args: unknown[]) => freezeAtom(createAtom(...args))) as never +} +``` diff --git a/src/vanilla/utils/freezeAtom.ts b/src/vanilla/utils/freezeAtom.ts index 585274bf17..945a3705b2 100644 --- a/src/vanilla/utils/freezeAtom.ts +++ b/src/vanilla/utils/freezeAtom.ts @@ -16,6 +16,7 @@ const deepFreeze = (obj: unknown) => { export function freezeAtom>( anAtom: AtomType, ): AtomType + export function freezeAtom( anAtom: WritableAtom, ): WritableAtom { @@ -48,11 +49,14 @@ export function freezeAtom( return anAtom } +/** + * @deprecated Define it on users end + */ export function freezeAtomCreator< CreateAtom extends (...args: unknown[]) => Atom, ->(createAtom: CreateAtom): CreateAtom -export function freezeAtomCreator( - createAtom: (...args: unknown[]) => WritableAtom, -): (...args: unknown[]) => WritableAtom { - return (...args) => freezeAtom(createAtom(...args)) +>(createAtom: CreateAtom): CreateAtom { + console.warn( + '[DEPRECATED] freezeAtomCreator is deprecated, define it on users end', + ) + return ((...args: unknown[]) => freezeAtom(createAtom(...args))) as never } diff --git a/tests/react/vanilla-utils/freezeAtom.test.tsx b/tests/react/vanilla-utils/freezeAtom.test.tsx index 52541827c2..37f2b74d84 100644 --- a/tests/react/vanilla-utils/freezeAtom.test.tsx +++ b/tests/react/vanilla-utils/freezeAtom.test.tsx @@ -1,6 +1,6 @@ import { StrictMode } from 'react' import { fireEvent, render } from '@testing-library/react' -import { it } from 'vitest' +import { afterEach, beforeEach, describe, it, vi } from 'vitest' import { useAtom } from 'jotai/react' import { atom } from 'jotai/vanilla' import { freezeAtom, freezeAtomCreator } from 'jotai/vanilla/utils' @@ -12,7 +12,6 @@ it('freezeAtom basic test', async () => { const Component = () => { const [obj, setObj] = useAtom(freezeAtom(objAtom)) - return ( <> @@ -32,38 +31,46 @@ it('freezeAtom basic test', async () => { await findByText('isFrozen: true') fireEvent.click(getByText('change')) - await findByText('isFrozen: true') }) -it('freezeAtomCreator basic test', async () => { - const createFrozenAtom = freezeAtomCreator(atom) - const objAtom = createFrozenAtom({ deep: {} }, (_get, set, _ignored?) => { - set(objAtom, { deep: {} }) +describe('freezeAtomCreator', () => { + let savedConsoleWarn: any + beforeEach(() => { + savedConsoleWarn = console.warn + console.warn = vi.fn() + }) + afterEach(() => { + console.warn = savedConsoleWarn }) - const Component = () => { - const [obj, setObj] = useAtom(objAtom) + it('freezeAtomCreator basic test', async () => { + const createFrozenAtom = freezeAtomCreator(atom) + const objAtom = createFrozenAtom({ deep: {} }, (_get, set, _ignored?) => { + set(objAtom, { deep: {} }) + }) - return ( - <> - -
- isFrozen: {`${Object.isFrozen(obj) && Object.isFrozen(obj.deep)}`} -
- - ) - } - - const { getByText, findByText } = render( - - - , - ) + const Component = () => { + const [obj, setObj] = useAtom(objAtom) + return ( + <> + +
+ isFrozen: {`${Object.isFrozen(obj) && Object.isFrozen(obj.deep)}`} +
+ + ) + } - await findByText('isFrozen: true') + const { getByText, findByText } = render( + + + , + ) - fireEvent.click(getByText('change')) + await findByText('isFrozen: true') - await findByText('isFrozen: true') + fireEvent.click(getByText('change')) + await findByText('isFrozen: true') + }) })