-
Notifications
You must be signed in to change notification settings - Fork 480
Closed
Description
Current behavior
According to hooks.js, useAsyncStorage is a wrapper rather than a hook.
// return a new object at every call
export function useAsyncStorage(key: string): AsyncStorageHook {
return {
getItem: (...args) => AsyncStorage.getItem(key, ...args), // assign a new prop at every call
setItem: (...args) => AsyncStorage.setItem(key, ...args),
mergeItem: (...args) => AsyncStorage.mergeItem(key, ...args),
removeItem: (...args) => AsyncStorage.removeItem(key, ...args),
};
}It will either trigger unexpected re-rendring:
const MyComponent = () => {
const wrapper = useAsyncStorage('mykey');
React.useEffect(() => {
wrapper.getItem().then(res => {
//...
})
}, [wrapper]); // <------ wrapper changes at every re-rendering
}const MyComponent = () => {
const { getItem } = useAsyncStorage('mykey');
React.useEffect(() => {
getItem().then(res => {
//...
})
}, [getItem]); // <------ getItem changes at every re-rendering
}Or eslint hooks warnings:
const MyComponent = () => {
const wrapper = useAsyncStorage('mykey');
React.useEffect(() => {
wrapper.getItem().then(res => {
//...
})
}, []); // <------ react-hooks/exhaustive-deps warning
}const wrapper = useAsyncStorage('mykey'); // <------ react-hooks/rules-of-hooks warning
const MyComponent = () => {
React.useEffect(() => {
wrapper.getItem().then(res => {
//...
})
}, []);
}A workaround is to disable warnings:
// eslint-disable-next-line react-hooks/rules-of-hooks
const wrapper = useAsyncStorage('mykey');
const MyComponent = () => {
React.useEffect(() => {
wrapper.getItem().then(res => {
//...
})
}, []);
}Expected behavior
- If
useAsyncStorageis not a standard hook, it should be renamed to something likewithAsyncStoragerather than starting withusewhich will be treated as a hook.
export function withAsyncStorage(key: string): AsyncStorageHook {
return {
getItem: (...args) => AsyncStorage.getItem(key, ...args),
setItem: (...args) => AsyncStorage.setItem(key, ...args),
mergeItem: (...args) => AsyncStorage.mergeItem(key, ...args),
removeItem: (...args) => AsyncStorage.removeItem(key, ...args),
};
}- If
useAsyncStorageis designed to be a standard hook, the returned value should bememo-ed
export function useAsyncStorage(key: string): AsyncStorageHook {
return React.useMemo(() => ({
getItem: (...args) => AsyncStorage.getItem(key, ...args),
setItem: (...args) => AsyncStorage.setItem(key, ...args),
mergeItem: (...args) => AsyncStorage.mergeItem(key, ...args),
removeItem: (...args) => AsyncStorage.removeItem(key, ...args),
}), []);
}- This should be documented
Repro steps
Environment
- Platforms tested:
- Android
- iOS
- macOS
- Windows
- AsyncStorage version:
- Expo version:
- Environment:
- Logs/Errors that may be relevant:
simenandre and goleary
Metadata
Metadata
Assignees
Labels
No labels