Skip to content

Commit

Permalink
fix: Make clearOnDefault: true by default (#700)
Browse files Browse the repository at this point in the history
  • Loading branch information
franky47 authored Oct 23, 2024
1 parent c96f238 commit 56c223f
Show file tree
Hide file tree
Showing 12 changed files with 54 additions and 37 deletions.
2 changes: 1 addition & 1 deletion packages/adapters/react/src/components/search-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { parseAsString, useQueryStates } from 'nuqs'

export function SearchInput() {
const [{ search }, setSearch] = useQueryStates({
search: parseAsString.withDefault('').withOptions({ clearOnDefault: true })
search: parseAsString.withDefault('')
})
return (
<input
Expand Down
2 changes: 1 addition & 1 deletion packages/adapters/remix/app/components/search-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { parseAsString, useQueryStates } from 'nuqs'

export function SearchInput() {
const [{ search }, setSearch] = useQueryStates({
search: parseAsString.withDefault('').withOptions({ clearOnDefault: true })
search: parseAsString.withDefault('')
})
return (
<input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ const gameParser = createParser<GameState>({
function useGameEngine() {
const [{ board, status }, setGameState] = useQueryState(
'board',
gameParser
.withDefault(defaultState)
.withOptions({ clearOnDefault: true, history: 'push' })
gameParser.withDefault(defaultState).withOptions({ history: 'push' })
)
const play = useCallback(
(i: number, j: number) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/e2e/cypress/e2e/clearOnDefault.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

it('Clears the URL when setting the default value when `clearOnDefault` is used', () => {
cy.visit(
'/app/clearOnDefault?a=a&b=b&array=1,2,3&json-ref={"egg":"spam"}&json-new={"egg":"spam"}'
'/app/clearOnDefault?a=a&b=b&array=1,2,3&json-ref={"egg":"spam"}&json-new={"egg":"spam"}&keepMe=init'
)
cy.contains('#hydration-marker', 'hydrated').should('be.hidden')
cy.get('button').click()
cy.location('search').should('eq', '?a=')
cy.location('search').should('eq', '?a=&keepMe=')
})
21 changes: 10 additions & 11 deletions packages/e2e/src/app/app/clearOnDefault/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
parseAsArrayOf,
parseAsInteger,
parseAsJson,
parseAsString,
useQueryState
} from 'nuqs'
import { Suspense } from 'react'
Expand All @@ -22,26 +23,23 @@ const runtimePassthrough = (x: unknown) => x
function Client() {
const [, setA] = useQueryState('a')
const [, setB] = useQueryState('b', {
defaultValue: '',
clearOnDefault: true
defaultValue: ''
})
const [, setArray] = useQueryState(
'array',
parseAsArrayOf(parseAsInteger)
.withDefault([])
.withOptions({ clearOnDefault: true })
parseAsArrayOf(parseAsInteger).withDefault([])
)
const [, setJsonRef] = useQueryState(
'json-ref',
parseAsJson(runtimePassthrough)
.withDefault(defaultJSON)
.withOptions({ clearOnDefault: true })
parseAsJson(runtimePassthrough).withDefault(defaultJSON)
)
const [, setJsonNew] = useQueryState(
'json-new',
parseAsJson(runtimePassthrough)
.withDefault(defaultJSON)
.withOptions({ clearOnDefault: true })
parseAsJson(runtimePassthrough).withDefault(defaultJSON)
)
const [, keepMe] = useQueryState(
'keepMe',
parseAsString.withDefault('').withOptions({ clearOnDefault: false })
)
return (
<>
Expand All @@ -52,6 +50,7 @@ function Client() {
setArray([])
setJsonRef(defaultJSON)
setJsonNew({ ...defaultJSON })
keepMe('')
}}
>
Clear
Expand Down
1 change: 0 additions & 1 deletion packages/e2e/src/app/app/remapped-keys/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ function Client() {
activeTags: parseAsArrayOf(parseAsString).withDefault([])
},
{
clearOnDefault: true,
urlKeys: {
searchQuery: 'q',
pageNumber: 'page',
Expand Down
3 changes: 1 addition & 2 deletions packages/e2e/src/app/app/template/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ export default function Page() {

function Client() {
const [state, setState] = useQueryState('state', {
defaultValue: '',
clearOnDefault: true
defaultValue: ''
})
return (
<>
Expand Down
4 changes: 3 additions & 1 deletion packages/nuqs/src/defs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ export type Options = {
* Clear the key-value pair from the URL query string when setting the state
* to the default value.
*
* Defaults to `false` to keep backwards-compatiblity when the default value
* Defaults to `true` to keep URLs clean.
*
* Set it to `false` to keep backwards-compatiblity when the default value
* changes (prefer explicit URLs whose meaning don't change).
*/
clearOnDefault?: boolean
Expand Down
39 changes: 28 additions & 11 deletions packages/nuqs/src/serializer.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { describe, expect, test } from 'vitest'
import type { Options } from './defs'
import {
parseAsArrayOf,
parseAsBoolean,
Expand Down Expand Up @@ -85,18 +86,32 @@ describe('serializer', () => {
const result = serialize('?str=foo&external=kept', null)
expect(result).toBe('?external=kept')
})
test('clears value when setting the default value when `clearOnDefault` is used', () => {
test('clears value when setting the default value (`clearOnDefault: true` is the default)', () => {
const serialize = createSerializer({
int: parseAsInteger.withOptions({ clearOnDefault: true }).withDefault(0),
str: parseAsString.withOptions({ clearOnDefault: true }).withDefault(''),
bool: parseAsBoolean
.withOptions({ clearOnDefault: true })
.withDefault(false),
arr: parseAsArrayOf(parseAsString)
.withOptions({ clearOnDefault: true })
.withDefault([]),
int: parseAsInteger.withDefault(0),
str: parseAsString.withDefault(''),
bool: parseAsBoolean.withDefault(false),
arr: parseAsArrayOf(parseAsString).withDefault([]),
json: parseAsJson(x => x).withDefault({ foo: 'bar' })
})
const result = serialize({
int: 0,
str: '',
bool: false,
arr: [],
json: { foo: 'bar' }
})
expect(result).toBe('')
})
test('keeps value when setting the default value when `clearOnDefault: false`', () => {
const options: Options = { clearOnDefault: false }
const serialize = createSerializer({
int: parseAsInteger.withOptions(options).withDefault(0),
str: parseAsString.withOptions(options).withDefault(''),
bool: parseAsBoolean.withOptions(options).withDefault(false),
arr: parseAsArrayOf(parseAsString).withOptions(options).withDefault([]),
json: parseAsJson(x => x)
.withOptions({ clearOnDefault: true })
.withOptions(options)
.withDefault({ foo: 'bar' })
})
const result = serialize({
Expand All @@ -106,6 +121,8 @@ describe('serializer', () => {
arr: [],
json: { foo: 'bar' }
})
expect(result).toBe('')
expect(result).toBe(
'?int=0&str=&bool=false&arr=&json={%22foo%22:%22bar%22}'
)
})
})
5 changes: 4 additions & 1 deletion packages/nuqs/src/serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ export function createSerializer<
parser.defaultValue !== undefined &&
(parser.eq ?? ((a, b) => a === b))(value, parser.defaultValue)

if (value === null || (parser.clearOnDefault && isMatchingDefault)) {
if (
value === null ||
((parser.clearOnDefault ?? true) && isMatchingDefault)
) {
search.delete(key)
} else {
search.set(key, parser.serialize(value))
Expand Down
4 changes: 2 additions & 2 deletions packages/nuqs/src/useQueryState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ export function useQueryState<T = string>(
serialize = String,
eq = (a, b) => a === b,
defaultValue = undefined,
clearOnDefault = false,
clearOnDefault = true,
startTransition
}: Partial<UseQueryStateOptions<T>> & {
defaultValue?: T
Expand All @@ -223,7 +223,7 @@ export function useQueryState<T = string>(
parse: x => x as unknown as T,
serialize: String,
eq: (a, b) => a === b,
clearOnDefault: false,
clearOnDefault: true,
defaultValue: undefined
}
) {
Expand Down
2 changes: 1 addition & 1 deletion packages/nuqs/src/useQueryStates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function useQueryStates<KeyMap extends UseQueryStatesKeysMap>(
scroll = false,
shallow = true,
throttleMs = FLUSH_RATE_LIMIT_MS,
clearOnDefault = false,
clearOnDefault = true,
startTransition,
urlKeys = defaultUrlKeys
}: Partial<UseQueryStatesOptions<KeyMap>> = {}
Expand Down

0 comments on commit 56c223f

Please sign in to comment.