deno.land / x / jotai@v1.8.4 / tests / optimization.test.tsx
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287import { useEffect } from 'react'import { fireEvent, render, waitFor } from '@testing-library/react'import { atom, useAtom } from 'jotai'import { getTestProvider, itSkipIfVersionedWrite } from './testUtils'
const Provider = getTestProvider()
itSkipIfVersionedWrite( 'only relevant render function called (#156)', async () => { const count1Atom = atom(0) const count2Atom = atom(0)
let renderCount1 = 0 let renderCount2 = 0
const Counter1 = () => { const [count, setCount] = useAtom(count1Atom) ++renderCount1 return ( <> <div>count1: {count}</div> <button onClick={() => setCount((c) => c + 1)}>button1</button> </> ) }
const Counter2 = () => { const [count, setCount] = useAtom(count2Atom) ++renderCount2 return ( <> <div>count2: {count}</div> <button onClick={() => setCount((c) => c + 1)}>button2</button> </> ) }
const { getByText } = render( <Provider> <Counter1 /> <Counter2 /> </Provider> )
await waitFor(() => { getByText('count1: 0') getByText('count2: 0') }) const renderCount1AfterMount = renderCount1 const renderCount2AfterMount = renderCount2
fireEvent.click(getByText('button1')) await waitFor(() => { getByText('count1: 1') getByText('count2: 0') }) expect(renderCount1).toBe(renderCount1AfterMount + 1) expect(renderCount2).toBe(renderCount2AfterMount + 0)
fireEvent.click(getByText('button2')) await waitFor(() => { getByText('count1: 1') getByText('count2: 1') }) expect(renderCount1).toBe(renderCount1AfterMount + 1) expect(renderCount2).toBe(renderCount2AfterMount + 1) })
itSkipIfVersionedWrite( 'only render once using atoms with write-only atom', async () => { const count1Atom = atom(0) const count2Atom = atom(0) const incrementAtom = atom(null, (_get, set, _arg) => { set(count1Atom, (c) => c + 1) set(count2Atom, (c) => c + 1) })
let renderCount = 0
const Counter = () => { const [count1] = useAtom(count1Atom) const [count2] = useAtom(count2Atom) ++renderCount return ( <div> count1: {count1}, count2: {count2} </div> ) }
const Control = () => { const [, increment] = useAtom(incrementAtom) return <button onClick={increment}>button</button> }
const { getByText, findByText } = render( <Provider> <Counter /> <Control /> </Provider> )
await findByText('count1: 0, count2: 0') const renderCountAfterMount = renderCount
fireEvent.click(getByText('button')) await findByText('count1: 1, count2: 1') expect(renderCount).toBe(renderCountAfterMount + 1)
fireEvent.click(getByText('button')) await findByText('count1: 2, count2: 2') expect(renderCount).toBe(renderCountAfterMount + 2) })
itSkipIfVersionedWrite( 'useless re-renders with static atoms (#355)', async () => { // check out https://codesandbox.io/s/m82r5 to see the expected re-renders const countAtom = atom(0) const unrelatedAtom = atom(0)
let renderCount = 0
const Counter = () => { const [count, setCount] = useAtom(countAtom) useAtom(unrelatedAtom) ++renderCount
return ( <> <div>count: {count}</div> <button onClick={() => setCount((c) => c + 1)}>button</button> </> ) }
const { getByText, findByText } = render( <Provider> <Counter /> </Provider> )
await findByText('count: 0') const renderCountAfterMount = renderCount
fireEvent.click(getByText('button')) await findByText('count: 1') expect(renderCount).toBe(renderCountAfterMount + 1)
fireEvent.click(getByText('button')) await findByText('count: 2') expect(renderCount).toBe(renderCountAfterMount + 2) })
itSkipIfVersionedWrite( 'does not re-render if value is the same (#1158)', async () => { const countAtom = atom(0)
let renderCount = 0
const Counter = () => { const [count, setCount] = useAtom(countAtom) ++renderCount return ( <> <div>count: {count}</div> <button onClick={() => setCount((c) => c)}>noop</button> <button onClick={() => setCount((c) => c + 1)}>inc</button> </> ) }
const { getByText, findByText } = render( <Provider> <Counter /> </Provider> )
await findByText('count: 0') const renderCountAfterMount = renderCount
fireEvent.click(getByText('noop')) await findByText('count: 0') expect(renderCount).toBe(renderCountAfterMount + 0)
fireEvent.click(getByText('inc')) await findByText('count: 1') expect(renderCount).toBe(renderCountAfterMount + 1)
fireEvent.click(getByText('noop')) await findByText('count: 1') expect(renderCount).toBe(renderCountAfterMount + 1)
fireEvent.click(getByText('inc')) await findByText('count: 2') expect(renderCount).toBe(renderCountAfterMount + 2) })
it('no extra rerenders after commit with derived atoms (#1213)', async () => { const baseAtom = atom({ count1: 0, count2: 0 }) const count1Atom = atom((get) => get(baseAtom).count1) const count2Atom = atom((get) => get(baseAtom).count2)
let renderCount1 = 0 let renderCount1AfterCommit = 0
const Counter1 = () => { const [count1] = useAtom(count1Atom) ++renderCount1 useEffect(() => { renderCount1AfterCommit = renderCount1 }) return <div>count1: {count1}</div> }
let renderCount2 = 0 let renderCount2AfterCommit = 0
const Counter2 = () => { const [count2] = useAtom(count2Atom) ++renderCount2 useEffect(() => { renderCount2AfterCommit = renderCount2 }) return <div>count2: {count2}</div> }
const Control = () => { const [, setValue] = useAtom(baseAtom) const inc1 = () => { setValue((prev) => ({ ...prev, count1: prev.count1 + 1 })) } const inc2 = () => { setValue((prev) => ({ ...prev, count2: prev.count2 + 1 })) } return ( <div> <button onClick={inc1}>inc1</button> <button onClick={inc2}>inc2</button> </div> ) }
const { getByText } = render( <Provider> <Counter1 /> <Counter2 /> <Control /> </Provider> )
await waitFor(() => { getByText('count1: 0') getByText('count2: 0') }) expect(renderCount1 > 0).toBe(true) expect(renderCount2 > 0).toBe(true)
fireEvent.click(getByText('inc1')) await waitFor(() => { getByText('count1: 1') getByText('count2: 0') }) expect(renderCount1).toBe(renderCount1AfterCommit)
fireEvent.click(getByText('inc2')) await waitFor(() => { getByText('count1: 1') getByText('count2: 1') }) expect(renderCount2).toBe(renderCount2AfterCommit)
fireEvent.click(getByText('inc1')) await waitFor(() => { getByText('count1: 2') getByText('count2: 1') }) expect(renderCount1).toBe(renderCount1AfterCommit)})
Version Info