我有以下钩子,允许从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]
}
我正在尝试测试以下两件事
- 挂钩值在 处初始化
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(...)
,指的setValue
是useEffect
“安装时”发生的错误。我知道更改状态应该包含在一个act
中,但是这在初始化钩子期间是异步发生的。处理此错误的正确方法是什么?
- 使用以下测试将状态乐观地设置为新值:
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。测试成功完成,但出现上述错误。