I have a project in React Native that utilizes React Navigation as well as Asyncstorage in order to store data to be edited by child screens. Since we need to listen for changes to each key globally, I made the following Asyncstorage hook that utilizes an EventEmitter:
import AsyncStorage from "@react-native-async-storage/async-storage";import EventEmitter from "eventemitter3";import { useEffect, useState } from "react";const eventEmitter = new EventEmitter();/** * Acts as a react hook for AsyncStorage * @param id - ID of the element * @param defaultValue - Default value of the element * @returns A react hook of the element */export default function useStorage<Type>(id: string, defaultValue: Type): [Type, (value: Type) => Promise<void>] { const [version, setVersion] = useState(0); const [data, setData] = useState(defaultValue); // Grab Data const getData = async () => { const jsonData = await AsyncStorage.getItem(id); if (jsonData) setData(JSON.parse(jsonData) as Type); }; useEffect(() => { getData(); }, [version]); // Save Data const saveData = async (value: Type) => { const jsonData = JSON.stringify(value); await AsyncStorage.setItem(id, jsonData); setData(value); eventEmitter.emit(id); } useEffect(() => { let isMounted = true; const handleDataChange = () => { if (isMounted) { setVersion(v => v + 1); } } const unmount = () => { isMounted = false; eventEmitter.removeListener(id, handleDataChange); } eventEmitter.addListener(id, handleDataChange); return unmount; }, [id]); return [data, saveData];}
However, whenever I utilize it, I get very strange results including...
- Data not properly loading when the same key is on parent and child screen simultaneously
- Data not properly updating
- Hook not cleaning up properly
Am I missing something? What is causing all of these issues? Is there a better way of implementing this?
Note: I am aware React Redux exists, but I would prefer to avoid it if possible.