Skip to content

Commit

Permalink
fix(core): improve re-render behavior with useTransition (#1139)
Browse files Browse the repository at this point in the history
* add test

* Removing flushPending from suspensePromise

* conditional transition test

Co-authored-by: riemon <99447053+riemonyamada@users.noreply.github.com>
  • Loading branch information
dai-shi and hirokibeta authored May 10, 2022
1 parent 17de495 commit c0e1b09
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 2 deletions.
2 changes: 0 additions & 2 deletions src/core/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,6 @@ export const createStore = (
promiseOrValue
.then((value: Awaited<Value>) => {
setAtomValue(version, atom, value, dependencies, suspensePromise)
flushPending(version)
})
.catch((e) => {
if (e instanceof Promise) {
Expand All @@ -441,7 +440,6 @@ export const createStore = (
return e
}
setAtomReadError(version, atom, e, dependencies, suspensePromise)
flushPending(version)
})
)
return setAtomSuspensePromise(
Expand Down
59 changes: 59 additions & 0 deletions tests/transition.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Suspense, useEffect, useTransition } from 'react'
import { fireEvent, render } from '@testing-library/react'
import { atom, useAtomValue, useSetAtom } from 'jotai'
import { getTestProvider } from './testUtils'

const Provider = getTestProvider()

jest.mock('../src/core/useDebugState.ts')

const describeWithUseTransition =
typeof useTransition === 'function' ? describe : describe.skip

describeWithUseTransition('useTransition', () => {
it('no extra commit with useTransition (#1125)', async () => {
const countAtom = atom(0)
const delayedAtom = atom(async (get) => {
await new Promise((r) => setTimeout(r, 100))
return get(countAtom)
})

const commited: { pending: boolean; delayed: number }[] = []

const Counter = () => {
const setCount = useSetAtom(countAtom)
const delayed = useAtomValue(delayedAtom)
const [pending, startTransition] = useTransition()
useEffect(() => {
commited.push({ pending, delayed })
})
return (
<>
<div>delayed: {delayed}</div>
<button onClick={() => startTransition(() => setCount((c) => c + 1))}>
button
</button>
</>
)
}

const { getByText, findByText } = render(
<Provider>
<Suspense fallback="loading">
<Counter />
</Suspense>
</Provider>
)

await findByText('delayed: 0')

fireEvent.click(getByText('button'))
await findByText('delayed: 1')

expect(commited).toEqual([
{ pending: false, delayed: 0 },
{ pending: true, delayed: 0 },
{ pending: false, delayed: 1 },
])
})
})

1 comment on commit c0e1b09

@vercel
Copy link

@vercel vercel bot commented on c0e1b09 May 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.