Skip to content

Commit

Permalink
feat: use unique key when not specified
Browse files Browse the repository at this point in the history
  • Loading branch information
mbret committed Nov 26, 2023
1 parent 611b8a3 commit ed7258a
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 3 deletions.
21 changes: 21 additions & 0 deletions src/lib/queries/react/keys/nanoid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export const nanoid = (size = 21) =>
crypto.getRandomValues(new Uint8Array(size)).reduce((id, byte) => {
// It is incorrect to use bytes exceeding the alphabet size.
// The following mask reduces the random byte in the 0-255 value
// range to the 0-63 value range. Therefore, adding hacks, such
// as empty string fallback or magic numbers, is unnecessary because
// the bitmask trims bytes down to the alphabet size.
byte &= 63
if (byte < 36) {
// `0-9a-z`
id += byte.toString(36)
} else if (byte < 62) {
// `A-Z`
id += (byte - 26).toString(36).toUpperCase()
} else if (byte > 62) {
id += "-"
} else {
id += "_"
}
return id
}, "")
79 changes: 79 additions & 0 deletions src/lib/queries/react/mutations/useMutation.keys.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { afterEach, describe, expect, it } from "vitest"
import { render, cleanup } from "@testing-library/react"
import React, { useEffect } from "react"
import { useMutation } from "./useMutation"
import { QueryClientProvider } from "../Provider"
import { QueryClient } from "../../client/createClient"

afterEach(() => {
cleanup()
})

describe("useMutation", () => {
describe("Given two mutations without keys", () => {
describe("when first mutation has result", () => {
it("should not change the result of second mutation", async () => {
const client = new QueryClient()
const values = { mutation: [] as any, observedMutation: [] as any }

const Comp = () => {
const mutation = useMutation({
mutationFn: async () => 2
})

const observedMutation = useMutation({
mutationFn: async () => {}
})

useEffect(() => {
values.mutation.push(mutation)
values.observedMutation.push(observedMutation)
}, [observedMutation, mutation])

useEffect(() => {
mutation.mutate()
}, [])

// we only display content once all queries are done
// this way when we text string later we know exactly
return <>{mutation.data}</>
}

const { findByText } = render(
<React.StrictMode>
<QueryClientProvider client={client}>
<Comp />
</QueryClientProvider>
</React.StrictMode>
)

expect(await findByText("2")).toBeDefined()

expect(values.mutation).toMatchObject([
{
data: undefined,
status: "idle"
},
{
data: undefined,
status: "idle"
},
{
data: undefined,
status: "loading"
},
{
data: 2,
status: "success"
}
])
expect(values.observedMutation).toMatchObject(
Array.from({ length: 4 }).map(() => ({
data: undefined,
status: "idle"
}))
)
})
})
})
})
7 changes: 4 additions & 3 deletions src/lib/queries/react/mutations/useMutation.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { useLiveRef } from "../../../utils/useLiveRef"
import { type MonoTypeOperatorFunction, identity } from "rxjs"
import { useObserve } from "../../../binding/useObserve"
import { useCallback, useEffect, useRef } from "react"
import { useCallback, useEffect } from "react"
import { type MutationOptions } from "../../client/mutations/types"
import { useQueryClient } from "../Provider"
import { type QueryKey } from "../../client/keys/types"
import { serializeKey } from "../keys/serializeKey"
import { nanoid } from "../keys/nanoid"
import { useConstant } from "../../../utils/useConstant"

export type AsyncQueryOptions<Result, Params> = Omit<
MutationOptions<Result, Params>,
Expand All @@ -21,7 +23,7 @@ export function useMutation<Args = void, R = undefined>(
) {
const client = useQueryClient()
const optionsRef = useLiveRef(options)
const defaultKey = useRef(["-1"]) // @todo dynamic
const defaultKey = useConstant(() => [nanoid()])
const key = serializeKey(options.mutationKey ?? defaultKey.current)

const result = useObserve(
Expand All @@ -37,7 +39,6 @@ export function useMutation<Args = void, R = undefined>(
error: undefined,
status: "idle"
}
// unsubscribeOnUnmount: optionsRef.current.cancelOnUnMount ?? false
},
[client, key]
)
Expand Down

0 comments on commit ed7258a

Please sign in to comment.