quarrant / mobx-persist-store

Persist and rehydrate observable properties in mobx store.
268 stars 14 forks source link

stringify:false doesnt work with @react-native-async-storage/async-storage #69

Open sergeykimaia opened 2 years ago

sergeykimaia commented 2 years ago

I've been trying to get a Map inside A map running, and the interior map kept returning [string,object]

thought it was due to me having stringify false

however with stringify:true I'm getting an uncaught exception and a crash when trying to modify persisted properties

quarrant commented 2 years ago

Hi! Show me your code

sergeykimaia commented 2 years ago

wrote an example: with stringify false it will crash when adding something to map without stringify it will crash after you reload the app

this example doesn't use @react-native-async-storage/async-storage but crash still happens

App.tsx:

import React, { FC, useEffect, useRef } from 'react';
import { observer } from 'mobx-react';
import { configure } from 'mobx';
import {
  SafeAreaView,
  Text,
  TextInput,
  TouchableOpacity,
  View,
} from 'react-native';
import { useStores } from './src/Stores/hooks/useStores';

configure({ enforceActions: 'never' });

const App: FC<AppProps> = observer(() => {
  const { rootStore } = useStores();
  const inputRef = useRef<{
    outerKey: string;
    innerKey: string;
    value: string;
  }>({ outerKey: '', innerKey: '', value: '' });
  const handleInnerKeyChange = (e: string) => {
    inputRef.current.innerKey = e;
  };
  const handleOuterKeyChange = (e: string) => {
    inputRef.current.outerKey = e;
  };
  const handleValueChange = (e: string) => {
    inputRef.current.value = e;
  };

  const handleAddToStore = () => {
    rootStore.setMyMap(
      inputRef.current.outerKey,
      inputRef.current.innerKey,
      inputRef.current.value
    );
  };

  return (
    <SafeAreaView>
      <View style={{ padding: 16 }}>
        <Text>{`Map<OuterKey,Map<InnerKey,Value>>`}</Text>
        <Text>outerKey:</Text>
        <TextInput
          onChangeText={handleOuterKeyChange}
          style={{ borderWidth: 1 }}
        />
        <Text>innerKey:</Text>
        <TextInput
          onChangeText={handleInnerKeyChange}
          style={{ borderWidth: 1 }}
        />
        <Text>Value:</Text>
        <TextInput
          onChangeText={handleValueChange}
          style={{ borderWidth: 1 }}
        />
        <TouchableOpacity onPress={handleAddToStore}>
          <Text>press to add</Text>
        </TouchableOpacity>
        <TouchableOpacity
          onPress={() => {
            rootStore.clear();
          }}
        >
          <Text>press clear</Text>
        </TouchableOpacity>
        <View>
          {Array.from(rootStore.myMap?.entries() || []).map((el) => (
            <View key={el[0]} style={{ borderBottomWidth: 1 }}>
              <Text>outerkey: {el[0]}</Text>
              <View style={{ flexDirection: 'row' }}>
                {Array.from(el[1]?.entries() || []).map((el2) => (
                  <View
                    key={el2[0]}
                    style={{ borderLeftWidth: 1, borderRightWidth: 1 }}
                  >
                    <Text>innerkey:{el2[0]}</Text>
                    <Text>outerKey:{el2[1]}</Text>
                  </View>
                ))}
              </View>
            </View>
          ))}
        </View>
      </View>
    </SafeAreaView>
  );
});

export default App;

rootStore.tsx:

import AsyncStorage from '@react-native-community/async-storage';
import { makeAutoObservable, observable } from 'mobx';
import { makePersistable, clearPersistedStore } from 'mobx-persist-store';

export class RootStore {
  constructor() {
    makeAutoObservable(this, {}, { autoBind: true });
    makePersistable(this, {
      name: 'rootStore',
      properties: ['myMap'],
      storage: AsyncStorage,
      stringify: false,
    });
  }

  myMap: Map<string, Map<string, string>> = new Map();

  setMyMap = (outerKey: string, innerKey: string, value: string) => {
    if (!outerKey || !innerKey || !value) {
      return;
    }
    if (!this.myMap) {
      this.myMap = new Map();
    }
    console.log('this.myMap', this.myMap.get);
    let innerMap = this.myMap.get(outerKey);
    console.log('innerMap', innerMap);
    if (!innerMap) {
      innerMap = observable(new Map());
      this.myMap.set(outerKey, innerMap);
    }
    innerMap.set(innerKey, value);
    console.log('mymap size', this.myMap.size);
  };

  clear = () => {
    clearPersistedStore(this).then(() => {
      this.myMap?.clear();
    });
  };
}

useStores.tsx:

import React from 'react';
import { storesContext } from '../contexts/storesContext';

export const useStores = () => React.useContext(storesContext);