Releases: MZanggl/promistate
usePromistate improvements
React's version of promistate now allows passing a dependencies array to update the callback in case it depends on local state (same as React's useCallback
).
const [search, setSearch] = React.useState('')
usePromistate(() => fetchArticles(search), {}, [search])
Additionally, some types have been improved.
Add delay option & isDelayOver field
By checking the new field isDelayOver
in conjunction with isPending
, this lets you avoid flashing loading spinners for fast requests.
This release adds
- new field
isDelayOver
to the result of promistate. - new option
delay
: Specifies after how many msisDelayOver
will be set to true. Defaults to 200ms.
Programmatically set error
Sometimes you may wish to set the error programmatically, unrelated to the actual promise.
import promistate from 'promistate'
const promise = promistate(() => fetch('...'))
promise.error = new Error('internal error')
or with the react hook:
import { usePromistate } from 'promistate/lib/react'
const [promise, actions] = usePromistate(() => fetch('...'))
actions.setError(new Error('internal error'))
listen API & React Hooks support
Added
listen API
There is a small but powerful new listen API to catch any state changes. This allows promistate to be used outside of vue-like reactivity systems ( vue, alpine or angular). It opens promistate up for use in react.js, svelte and EVEN Vanilla JS (see README for examples, more coming...).
React hooks support
Thanks to the listen API, promistate now has first-class support for react. Here is an example
import React from "react";
import { usePromistate } from "promistate/lib/react";
export default function App() {
const [todosPromise, todoActions] = usePromistate(somePromise);
// todosPromise.value, todosPromise.isPending, ...
// todoActions.load(), todoActions.reset(), todoActions.setValue('new Value')
}
Fixes
- Mutating a value directly was previously not causing stale loads to be ignored when
ignoreStaleLoad
was enabled
Add option to ignore stale promise loads + cancelling promises
Added
ignoreStaleLoad
option
Imagine you have a button "send request". Sending the request will make a new button appear to cancel the request again. When you cancel the request, you can again click "send request".
This comes with two complexities
- Canceling the request should not change the state once the promise settles
- Requesting > canceling (reset) > requesting should not change the state with the result of the first request, only with the result of the second request
Pass { ignoreStaleLoad: true }
in the configurations and you are good to go. promistate
takes it from here.
This way, when on cancel you call the "reset" method it will ignore any previously pending promise once they settle. Same way if you call "load" twice (or load, reset, load), the first "load" will be completely ignored).
Fixed
Previously I was not exposing the types we used, which makes it hard to build on top of promistate
(e.g. for a react hook, which will come soon)
Added timesSettled & resolve synchronous callbacks
Added
"timesSettled" is a new member of the state and it holds a count how many times load() was settled.
Fixed
Code like this crashed
promistate(id => {
return id ? fetch('...') ? null
})
because it was expected that the callback always returns a promise.
Breaking change: import
Import changed from
import { promistate, Status } from 'promistate
to
import promistate, { PromistateStatus } from 'promistate
make isEmpty an accessor so it reacts to value mutations
See test for details
test('isEmpty reacts to value changes', async (assert) => {
const state = promistate(() => [], { defaultValue: [1] })
assert.isFalse(state.isEmpty)
state.value = []
assert.isTrue(state.isEmpty)
})
Custom isEmpty check & proper context binding
- Feature: New configuration to pass a custom
isEmpty
check. This is useful if the response is something like{ page: 1, items: [] }
- Bugfix: Bind the context of promistate result to the callback method. This is useful if you need to append a response to the previous one, or pass parts of it in the request (e.g. page token)