Skip to content

Commit

Permalink
deprecate freezeAtomCreator (#2490)
Browse files Browse the repository at this point in the history
  • Loading branch information
dai-shi committed Apr 7, 2024
1 parent 93a28f4 commit 2abd51c
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 43 deletions.
23 changes: 12 additions & 11 deletions docs/guides/debugging.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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<unknown>,
>(createAtom: CreateAtom): CreateAtom {
return ((...args: unknown[]) => freezeAtom(createAtom(...args))) as never
}
```
14 changes: 9 additions & 5 deletions src/vanilla/utils/freezeAtom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const deepFreeze = (obj: unknown) => {
export function freezeAtom<AtomType extends Atom<unknown>>(
anAtom: AtomType,
): AtomType

export function freezeAtom(
anAtom: WritableAtom<unknown, unknown[], unknown>,
): WritableAtom<unknown, unknown[], unknown> {
Expand Down Expand Up @@ -48,11 +49,14 @@ export function freezeAtom(
return anAtom
}

/**
* @deprecated Define it on users end
*/
export function freezeAtomCreator<
CreateAtom extends (...args: unknown[]) => Atom<unknown>,
>(createAtom: CreateAtom): CreateAtom
export function freezeAtomCreator(
createAtom: (...args: unknown[]) => WritableAtom<unknown, unknown[], unknown>,
): (...args: unknown[]) => WritableAtom<unknown, unknown[], unknown> {
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
}
61 changes: 34 additions & 27 deletions tests/react/vanilla-utils/freezeAtom.test.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -12,7 +12,6 @@ it('freezeAtom basic test', async () => {

const Component = () => {
const [obj, setObj] = useAtom(freezeAtom(objAtom))

return (
<>
<button onClick={setObj}>change</button>
Expand All @@ -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 (
<>
<button onClick={setObj}>change</button>
<div>
isFrozen: {`${Object.isFrozen(obj) && Object.isFrozen(obj.deep)}`}
</div>
</>
)
}

const { getByText, findByText } = render(
<StrictMode>
<Component />
</StrictMode>,
)
const Component = () => {
const [obj, setObj] = useAtom(objAtom)
return (
<>
<button onClick={setObj}>change</button>
<div>
isFrozen: {`${Object.isFrozen(obj) && Object.isFrozen(obj.deep)}`}
</div>
</>
)
}

await findByText('isFrozen: true')
const { getByText, findByText } = render(
<StrictMode>
<Component />
</StrictMode>,
)

fireEvent.click(getByText('change'))
await findByText('isFrozen: true')

await findByText('isFrozen: true')
fireEvent.click(getByText('change'))
await findByText('isFrozen: true')
})
})

0 comments on commit 2abd51c

Please sign in to comment.