diff --git a/packages/e2e/cypress/e2e/repro-702.cy.js b/packages/e2e/cypress/e2e/repro-702.cy.js new file mode 100644 index 00000000..cbc3fcf8 --- /dev/null +++ b/packages/e2e/cypress/e2e/repro-702.cy.js @@ -0,0 +1,24 @@ +/// + +describe('repro-702', () => { + it('mounts components with the correct state on load', () => { + cy.visit('/app/repro-702?a=test&b=test') + cy.get('#conditional-a-useQueryState').should('have.text', 'test pass') + cy.get('#conditional-a-useQueryStates').should('have.text', 'test pass') + cy.get('#conditional-b-useQueryState').should('have.text', 'test pass') + cy.get('#conditional-b-useQueryStates').should('have.text', 'test pass') + }) + + it('mounts components with the correct state after an update', () => { + cy.visit('/app/repro-702') + cy.contains('#hydration-marker', 'hydrated').should('be.hidden') + + cy.get('#trigger-a').click() + cy.get('#conditional-a-useQueryState').should('have.text', 'test pass') + cy.get('#conditional-a-useQueryStates').should('have.text', 'test pass') + + cy.get('#trigger-b').click() + cy.get('#conditional-b-useQueryState').should('have.text', 'test pass') + cy.get('#conditional-b-useQueryStates').should('have.text', 'test pass') + }) +}) diff --git a/packages/e2e/src/app/app/repro-702/page.tsx b/packages/e2e/src/app/app/repro-702/page.tsx new file mode 100644 index 00000000..47c952af --- /dev/null +++ b/packages/e2e/src/app/app/repro-702/page.tsx @@ -0,0 +1,110 @@ +'use client' + +import { parseAsString, useQueryState, useQueryStates } from 'nuqs' +import { Suspense, useRef } from 'react' + +export default function Page() { + return ( + + + + ) +} + +function Client() { + return ( + <> + + + + + + ) +} + +// using useQueryState +function TriggerA() { + const [, setState] = useQueryState('a') + return ( + + ) +} + +// using useQueryStates +function TriggerB() { + const [, setState] = useQueryStates({ + b: parseAsString + }) + return ( + + ) +} + +function SwitchComponentA() { + const [x] = useQueryState('a') + if (x === 'test') { + return + } + return null +} + +function SwitchComponentB() { + const [x] = useQueryState('b') + if (x === 'test') { + return + } + return null +} + +function ConditionalComponentA() { + const nullCheckUseQueryState = useRef(false) + const nullCheckUseQueryStates = useRef(false) + const [fromUseQueryState] = useQueryState('a') + const [{ a: fromUseQueryStates }] = useQueryStates({ a: parseAsString }) + + if (fromUseQueryState === null) { + nullCheckUseQueryState.current = true + } + if (fromUseQueryStates === null) { + nullCheckUseQueryStates.current = true + } + + return ( + <> +
+ {fromUseQueryState} {nullCheckUseQueryState.current ? 'fail' : 'pass'} +
+
+ {fromUseQueryStates} {nullCheckUseQueryStates.current ? 'fail' : 'pass'} +
+ + ) +} + +function ConditionalComponentB() { + const nullCheckUseQueryState = useRef(false) + const nullCheckUseQueryStates = useRef(false) + const [fromUseQueryState] = useQueryState('b') + const [{ b: fromUseQueryStates }] = useQueryStates({ b: parseAsString }) + + if (fromUseQueryState === null) { + nullCheckUseQueryState.current = true + } + if (fromUseQueryStates === null) { + nullCheckUseQueryStates.current = true + } + return ( + <> +
+ {fromUseQueryState} {nullCheckUseQueryState.current ? 'fail' : 'pass'} +
+
+ {fromUseQueryStates} {nullCheckUseQueryStates.current ? 'fail' : 'pass'} +
+ + ) +}