Effet
L'API effect complète l'API state en offrant une meilleure façon de réagir à plusieurs changements d'état en fonction de ce que vous devez exécuter.
type EffectSubscriber<T> = (value: T | undefined) => undefined | T
type EffectUnSubscriber = () => void
effect: <T>(sub: EffectSubscriber<T>) => EffectUnSubscriberL'API state permet de s'abonner aux modifications de sa valeur.
const [count, updateCount] = state(0, () => {
// react to changes
})
updateCount(10)C'est idéal si vous souhaitez effectuer des effets secondaires liés à un seul état. Pour effectuer des effets secondaires pour plusieurs états, vous aurez besoin de l'API effect.
const [count, updateCount] = state(0)
effect(() => {
// react to changes
})
updateCount(10)EffectUnSubscriber
Certains effets secondaires peuvent persister de manière continue en tant qu’effet global lié à quelque chose de spécifique. D'autres doivent être nettoyés chaque fois que la portée dans laquelle ils sont définis disparaît.
const cleanEffect = effect(() => {
// react to changes
})
cleanEffect()Comment ça marche ?
Lorsque vous appelez un StateGetter dans la fonction de rappel effect, le effect prend conscience de l'état et cette détection se fait de manière synchrone.
L'effet appelle le rappel fourni dès qu'il est déclaré afin qu'il prenne conscience des états appelés à l'intérieur.
effect(() => {
console.log(count()) // will log right away
})Le effect regroupe également les mises à jour, ce qui vous permet de mettre à jour plusieurs états à la fois et de n'avoir qu'une seule réaction.
effect(() => {
console.log(count(), total())
// prints: 0 0 on initiation
// prints: 1 1 on update of both values
})
setCount((prev) => prev + 1)
setTotal((prev) => prev + 1)La mise à jour par lots est utile mais le effect comprend également l'initialisation qui vous permet d'effectuer un calcul groupé au chargement et de ne l'exécuter qu'une seule fois après avoir terminé.
effect(() => {
console.log(count())
// prints: 0 on initiation
// print: 100 after the while loop completes
})
while (count() < 100) {
setCount((prev) => prev + 1)
}Mise en cache
Le effect vous permet de renvoyer les valeurs mises en cache et fournies dans le rappel pour la prochaine fois. C’est idéal pour suivre les modifications au fil des mises à jour.
Par exemple, effectuez un effet anti-rebond sur les modifications de la valeur de recherche.
const [search, setSearch] = state('')
const [searchResults, updateSearchResults] = state([])
effect((timer) => {
clearTimeout(timer)
// so the effect becomes aware of "search" state
const searchValue = search()
return setTimeout(async () => {
const response = api.search({ searchValue })
updateSearchResults(response.results)
}, 300)
})Effet asynchrone
Le effect fonctionne de manière synchrone. C'est ainsi qu'il détecte les états à l'intérieur et met en cache les données.
Cependant, le rappel que vous fournissez au effect peut être asynchrone si vous le souhaitez vraiment.
effect(async () => {
try {
const res = await fetch(
`https://randomuser.me/api/?page=${count()}&results=10&seed=markup`
)
console.log(await res.json())
} catch (e) {
console.error(e)
}
})Si vous le faites, les données mises en cache seront la promesse renvoyée par la fonction et non les données que vous renvoyez du rappel asynchrone. Cela signifie que vous devez résoudre les données mises en cache pour obtenir la valeur.
effect(async (res = Promise.resolve(0)) => {
const result = count() + (await res)
console.log(result)
return result
})Effet imbriqué
Vous pouvez imbriquer effect pour suivre différentes valeurs. Cela permet au corps de votre effect de réagir indépendamment tandis que différents effets suivent différents états.
const unsub = effect(() => {
console.log('outer', count())
effect(() => {
console.log('inner', count())
})
})
unsub() // clears all effectsSi vous souhaitez effacer tous les effets, vous pouvez vous désinscrire du effect le plus externe et qui s'occupera de tous les enfants effect pour vous. Cependant, vous devez suivre les effets internes car chaque fois que l'effet externe est appelé, un nouvel effet interne sera créé.