0

我有以下钩子,允许从AsyncStorage.

export default <T>(key: string, defaultValue: T | null): [T | null, (value: T) => Promise<void>, () => Promise<void>] => {
    const [value, setValue] = useState<T | null>(null); // always initializes at null

    // set at value retrieved from storage, or at the default value
    useEffect(() => {
        (async () => {
            const storageValue = await getStorageValue(key);
            if (storageValue === null) {
                setValue(defaultValue); // LOCATION OF THE ERROR 1
            } else {
                setValue(storageValue);
            }
        })()
    }, [])

    const setStorageValue = async (value: T): Promise<void> => {

        // Optmistically set value
        setValue(value);

        // Storage in async storage
        await AsyncStorage.setItem(
            key,
            JSON.stringify(value)
        ).catch(() => {
            console.error(`useAsyncStorage > setStorageValue > Could not set value '${value}' to key '${key}'`)
        })
    }

    const getStorageValue = async (key: string) => {
        try {
            const value = await AsyncStorage.getItem(key);

            if (value !== null) return JSON.parse(value);

            return null
        } catch (error) {
            console.error(`useAsyncStorage > getStorageValue > Could not get value for stored key '${key}'`)
            return null
        }
    }

    const removeFromStorage = async () => {
        try {
            await AsyncStorage.removeItem(key);
            setValue(defaultValue)
        }
        catch (exception) {
            console.error(`useAsyncStorage > removeFromStorage > Could not remove value for stored key '${key}'`)
            console.error(exception)
        }
    }

    return [value, setStorageValue, removeFromStorage]
}

我正在尝试测试以下两件事

  1. 挂钩值在 处初始化null,表示该值仍应从存储中检索,这发生在异步中。

为此,我进行了以下测试:

it("state initializes at null", async () => {
   const defaultValue = 3;
   const { result } = renderHook(() => useAsyncStorage('key', defaultValue));
   expect(result.current[0]).toBe(null); // should be null immediately after
});

然而,这给了我一个错误 An update to TestComponent inside a test was not wrapped in act(...),指的setValueuseEffect“安装时”发生的错误。我知道更改状态应该包含在一个act中,但是这在初始化钩子期间是异步发生的。处理此错误的正确方法是什么?

  1. 使用以下测试将状态乐观地设置为新值:
it("state is optimistically set to the new value", async () => {
    const defaultValue = 3;
    const newValue = 1;
    const { result, unmount } = renderHook(() => useAsyncStorage('key', defaultValue));
    await new Promise((r) => setTimeout(r, 2000)); // Manual wait for the `useEffect` to complete before setting a new value.

    await act(async () => await result.current[1](newValue))

    // Expect optimistic update, thus immediately set of value
    await waitFor(() => expect(result.current[0]).toBe(newValue))
});

这现在给了我错误: You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);。然而,我将已经包裹act在一个await. 那么这里发生了什么,我怎样才能摆脱这个错误?

PS。测试成功完成,但出现上述错误。

4

0 回答 0