Guidance for proper design patterns, random errors

I’m building a React-Native app using Realm. It took a while to land on a pattern that works for my app after reading through the docs and a bunch of the GitHub Issues. I have something that works but I’m still getting random errors that don’t make sense such as the mysterious

Error: The Realm is already in a write transaction

I’m using a singleton Realm in a Context Provider like so (I’ve commented out the realm.close because when React Native reloads after modifying/saving files I see more errors):

const RealmContext = React.createContext<Realm|null>(null);

export const RealmProvider: React.FC = ({children}) => {
    const [realm, setRealm] =           React.useState<Realm|null>(null);
    React.useEffect(() => {
        Realm.open(REALM_CONFIG).then((openRealm) => {
            console.log(`${moment().format(TIME_FORMAT)} realm opened`);
            setRealm(openRealm);
        });
        return () => {
            //realm?.close();
        };
    }, []);
    return (
        <>
            <RealmContext.Provider value={realm}>
                {children}
            </RealmContext.Provider>
        </>
    );
};

export const useRealm = () => React.useContext(RealmContext);

For my listeners I’ve created a few custom hooks that more or less allow me to integrate with React’s useState as shown.

export default function useRealmObjectHook<T>({ source, primaryKey }: RealmObjectParams<T>) {
    const realm = useRealm();
    const [data, setData] = React.useState<Data<T>>();
    const query = React.useMemo(() => {
        if (realm && source && primaryKey) {
            return realm.objectForPrimaryKey<T>(source, primaryKey);
        }
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [source, primaryKey] );
    const safeAddListener = React.useCallback((callback:any) => {
        if (realm && query) {
            if (realm.isInTransaction) {
                setTimeout(() => { safeAddListener(callback); }, 50);
                console.log(`realm.isInTransaction === true; ${source} ${primaryKey}`);
            } else {
                query.addListener(callback);
            }
        }
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [realm, query]);
    React.useEffect(() => {
        function handleChange(_object: T, changes: Realm.ObjectChangeSet) {
            const { changedProperties, deleted } = changes;
            if (changedProperties.length > 0 || deleted) {
                //console.log('setting data');
                setData({
                    data: (_object),
                    a: moment().valueOf(), //note this hack here as described in a GitHub post
                });
            }
        }
        if (query) {
            //console.log('addListener', query);
            setData({
                data: query,
                a: moment().valueOf(),
            });
            safeAddListener(handleChange);
        }
        return () => {
            if (query) {
                //console.log('removeAllListeners');
                query.removeAllListeners();
            }
        };
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [query]);
    return data?.data;
}

My app has a Websocket that receives data and writes to the Realm database. All of the writes happen in a separate file and look like this:

export const updateUser = (apiUser: ApiUser) => {
    return new Promise((resolve, reject) => {
        const realm = new Realm(REALM_CONFIG);
        realm.write(() => {
            realm.create(User.schema.name, new User(apiUser), Realm.UpdateMode.Modified);
        });
        resolve({});
    });
};

As you can see, when I write to the database, I always ‘instantiate’ a new Realm object and pass in the same REALM_CONFIG that the RealmContext also uses. Per the docs, this is the synchronous way of opening a Realm. To me, opening and writing to the realm in this manner should be completely safe. However as I indicated, I still see error I noted above frequently especially when the app is starting up and I’m creating a bunch of listeners. I gathered from this comment (Realm is already in a write transaction inside live collection listener!? · Issue #1188 · realm/realm-js · GitHub) that I only needed to check IsInTransaction when I do a write transaction while in a listener which I’m not doing. It kind of feels like even though I’m instantiating a new realm when writing that it’s still using the same one. It feels like I’m misunderstanding a fundamental concept. Anyone know what’s going on here?

Thanks