效果

effect API 补充了 state API,提供了一种更好的方法来根据您需要执行的内容对多个状态更改做出反应。

typescript
type EffectSubscriber<T> = (value: T | undefined) => undefined | T
type EffectUnSubscriber = () => void

effect: <T>(sub: EffectSubscriber<T>) => EffectUnSubscriber

state API 允许您订阅其值的更改。

javascript
const [count, updateCount] = state(0, () => {
    // react to changes
})

updateCount(10)

如果您想执行与单个状态相关的副作用,这非常有用。要执行多个状态的副作用,您将需要 effect API。

javascript
const [count, updateCount] = state(0)

effect(() => {
    // react to changes
})

updateCount(10)

EffectUnSubscriber

一些副作用可能会持续存在,作为对特定事物的全局影响。每当定义其他对象的范围消失时,就需要清理它们。

javascript
const cleanEffect = effect(() => {
    // react to changes
})

cleanEffect()

它是如何运作的?

当您在 effect 回调函数内调用 StateGetter 时,effect 会意识到该状态,并且此检测是同步完成的。

该效果在声明后立即调用提供的回调,以便它了解内部调用的状态。

javascript
effect(() => {
    console.log(count()) // will log right away
})

effect 还可以批量更新,使您可以一次更新多个状态并且只有一个反应。

javascript
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)

批量更新很有用,但 effect 也理解初始化,这允许您在加载时进行大量计算,并且只在完成后运行一次。

javascript
effect(() => {
    console.log(count())
    // prints: 0 on initiation
    // print: 100 after the while loop completes
})

while (count() < 100) {
    setCount((prev) => prev + 1)
}

缓存

effect 允许您返回缓存的值并在下次回调中提供。这对于跟踪更新中的更改非常有用。

例如,对搜索值更改执行去抖效果。

javascript
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)
})

异步效果

effect 同步工作。这就是它检测内部状态并缓存数据的方式。

但是,如果您确实愿意,向 effect 提供的回调可以是异步的。

javascript
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)
    }
})

如果这样做,缓存的数据将是函数返回的 Promise,而不是从异步回调返回的数据。这意味着您需要解析缓存的数据才能获取值。

javascript
effect(async (res = Promise.resolve(0)) => {
    const result = count() + (await res)

    console.log(result)

    return result
})

嵌套效应

您可以嵌套 effect 来跟踪不同的值。这允许 effect 的主体独立反应,同时不同的效果跟踪不同的状态。

javascript
const unsub = effect(() => {
    console.log('outer', count())
    effect(() => {
        console.log('inner', count())
    })
})

unsub() // clears all effects

如果您想清除所有效果,您可以从最外层的effect取消订阅,它将为您照顾所有子effect。但是,您必须跟踪内部效果,因为每当调用外部效果时,都会创建一个新的内部效果。

编辑本文档