Bot releases are visible (Hide)
Published by hazae41 about 2 years ago
CHANGES
document.update(async function* () {
yield { data: "My optimistic document" }
await new Promise(ok => setTimeout(ok, 5000))
// no return, will use the fetcher to get the new state
})
This is useful when you know the resource will be updated but want to display an optimistic state.
Also, { cache: "reload" }
will be passed to the fetcher in order to skip the cache, feel free to pass it to JS fetch or Axios or ignore it
Published by hazae41 about 2 years ago
BREAKING CHANGES
update(updater, params, aborter)
await document.update(async function* (previous) {
yield { data: "My optimistic document" }
return await postAsJson("/api/edit", "My updated document")
}, { timeout: 60 * 1000 })
CHANGES
Published by hazae41 about 2 years ago
BREAKING CHANGES
document.update(async function* (previous) {
yield { data: "My optimistic document" }
return await postAsJson("/api/edit", "My document")
})
Published by hazae41 about 2 years ago
BREAKING CHANGES
Data | Ref
in your first type parameterBEFORE: XSWR.single<Data, Error, Ref>(...)
NOW: XSWR.single<Data | Ref, Error>(...)
async function getDataRef(data: Data | Ref, more: XSWR.NormalizerMore) {
if ("ref" in data) return data
const schema = getDataSchema(data.id)
await schema.normalize(data, more)
return { ref: true, id: data.id } as Ref
}
See the docs for more details
CHANGES
first()
on a normalized scrolling resourcePublished by hazae41 about 2 years ago
BREAKING CHANGES
CHANGES
handle.suspend()
a super natural and easy way to suspend your componentsfunction Component() {
const { data, error, suspend } = useData()
// Throw the error
if (error) throw error
// Fetch and suspend until next state change
if (!data) throw suspend()
return <div>{JSON.stringify(data)}</div>
}
That's it, you have control over when you suspend and when your throw 🚀
Published by hazae41 about 2 years ago
BREAKING CHANGES
return XSWR.scroll<Data | string, Error, string>(url, fetcher)
This is because on scroll, previous pages are in normalized form, but the next page is in data form
newData = [...previousPages: Normalized[], nextPage: Data]
CHANGES
Published by hazae41 about 2 years ago
BREAKING CHANGES
make()
, Schema.make()
and Object constructors no longer need init
parameter, they will get data only once!mutate()
now accepts a functionmutate((currentState?: State) => State | undefined)
CHANGES
fetch()
and refetch()
will just return the current statePublished by hazae41 about 2 years ago
BREAKING CHANGES
D,E,N,K
; some types may break if you used type parameters beforeCHANGES
We'll use normalization for an array that contains items of type Data, each with an unique id
interface Data {
id: string
name: string
}
First, create a schema factory for an item
function getDataSchema(id: string) {
return XSWR.single<Data>(`/api/data?id=${id}`, fetchAsJson)
}
Then, create a normal for an item
A normal is an object that encapsulates your data, its schema, and a reference to your data (so we can delete the original data and just keep the reference)
function getDataNormal(data: Data) {
return new XSWR.Normal(data, getDataSchema(data.id), data.id)
}
Then, create a schema for your container, and create a normalizer, it will return then new structure of your container
In this case, all the array is mapped to normals, which will then automatically be replaced by references by XSWR
function getAllDataSchema() {
function normalizer(data: Data[]) {
return data.map(getDataNormal)
}
return XSWR.single<Data[], Error, string[]>(
`/api/data/all`,
fetchAsJson,
{ normalizer })
}
Notice the extra type parameter string[]
, it's the final type of our container, after normalization
That's it! No dependency needed, it just works!
You can find a full example in test/next/normalizer
Published by hazae41 about 2 years ago
NO BREAKING CHANGES
CHANGES
make
, Schema.make
, and Object constructors now accept initialize
as last optional parameter (default true) in order to initialize the object with the current state, it can be set to false for optimizing performances when you just need to call mutate
and don't need the data, for exampleconst object = make(getHelloSchema(), false) // Won't load the state in the object
await object.mutate({ data: "Hello World" })
Published by hazae41 about 2 years ago
BREAKING CHANGES
useAsyncLocalStorage("mycache")
Default prefix is xswr:
CHANGES
collect()
and unmount()
methods on all storagesPublished by hazae41 about 2 years ago
BREAKING CHANGES
CHANGES
async function fetchAsJson<T>(url: string, more: XSWR.PosterMore<T>) {
const { signal } = more
const res = await fetch(url, { signal })
const cooldown = Date.now() + (5 * 1000)
const expiration = Date.now() + (10 * 1000)
if (!res.ok) {
const error = new Error(await res.text())
return { error, cooldown, expiration } // implicit Date.now()
}
const data = await res.json() as T
return { data, time: data.time, cooldown, expiration } // explicit date.time (milliseconds)
}
Published by hazae41 about 2 years ago
NO BREAKING CHANGES
CHANGES
async function fetchAsJson<T>(url: string, more: XSWR.PosterMore<T>) {
const { signal } = more
const res = await fetch(url, { signal })
const cooldown = Date.now() + (5 * 1000)
const expiration = Date.now() + (10 * 1000)
if (!res.ok) {
const error = new Error(await res.text())
return { error, cooldown, expiration }
}
const data = await res.json() as T
return { data, cooldown, expiration }
}
This way you can still set expiration and cooldown
Published by hazae41 about 2 years ago
BREAKING CHANGES
refetch()
now cancels ongoing requests (unless it's an optimistic update)update()
no longer throws on error, it just mutates the state with the error (you can still check for error by checking the returned state)CHANGES
handle.aborter
is now available on optimistic updateshandle.optimistic
is now available to tell whether the ongoing request is optimisticPublished by hazae41 about 2 years ago
NO BREAKING CHANGE
CHANGES
const storage = new XSWR.IDBStorage("mydb")
function getHelloSchema() { // See the docs for the new schema pattern
return XSWR.single("/api/hello", fetchAsJson, { storage })
}
Published by hazae41 about 2 years ago
BREAKING CHANGES
XSWR.use
: XSWR.use(schema)
=> XSWR.use(factory, deps)
function getCatShema(id: string) {
return XSWR.single(["/api/cat", id], fetchAsJson)
}
function useCatBase(id: string) {
return XSWR.use(getCatSchema, [id])
}
It works like useMemo
but the deps are passed to the factory.
Published by hazae41 about 2 years ago
NO BREAKING CHANGES
CHANGES
// Create a schema for your resource
function getHelloSchema(id: string) {
return XSWR.single("/api/hello", fetchAsJson)
}
// Use it in a hook
function useHello(id: string) {
const handle = XSWR.use(getHelloSchema(id))
XSWR.useFetch(handle)
return handle
}
// Or in a function
function Setter() {
const { make } = XSWR.useXSWR()
const set = useCallback(async () => {
const object = make(getHelloSchema("123"))
await object.mutate({ data: "hello world" })
await object.refetch()
}, [make])
return <button onClick={set}>
Click me
</button>
}
Published by hazae41 about 2 years ago
NO BREAKING CHANGES
CHANGES
XSWR.ParamsProvider
to provide custom params to all children without changing the core providerexport default function Wrapper() {
return <XSWR.ParamsProvider
serializer={GZIP}>
<Page />
</XSWR.ParamsProvider>
}
Since params = { ...parent, ...current }
the downmost params will override.
If I then use a custom serializer in my handle, JSON will be used instead of GZIP.
useSingle(url, fetcher, { serializer: JSON })
Published by hazae41 about 2 years ago
NO BREAKING CHANGES
CHANGES
// Create a storage in the hook or at top-level
const storage = XSWR.useAsyncLocalStorage()
const handle = XSWR.useSingle(
"/api/hello",
fetchAsJson,
{ storage })
XSWR.useFetch(handle)
return handle
const handle = XSWR.useSingle(
"/api/hello",
fetchAsJson,
{ serializer: GZIP })
XSWR.useFetch(handle)
return handle
const handle = XSWR.useSingle(
"/api/hello",
fetchAsJson,
{ equals: deepCompare })
XSWR.useFetch(handle)
return handle
Published by hazae41 about 2 years ago
NO BREAKING CHANGES
CHANGES
Published by hazae41 about 2 years ago
NO BREAKING CHANGES
CHANGES