dai-shi / react-hooks-global-state

[NOT MAINTAINED] Simple global state for React with Hooks API without Context API
https://www.npmjs.com/package/react-hooks-global-state
MIT License
1.1k stars 62 forks source link

Offline saved data for React Native #43

Closed Temirtator closed 2 years ago

Temirtator commented 4 years ago

https://github.com/dai-shi/react-hooks-global-state/wiki/Persistence

is there any example for React Native here? And if not, then i think it would be great feature for this library. Thanks.

dai-shi commented 4 years ago

Hi, I wish somebody helps on it. Some quick questions:

  1. Do you mean to use AsyncStorage in RN?
  2. If the write operation is async, do you think the store should hold the old value or the new one while the async operation is in process?
Temirtator commented 4 years ago

@dai-shi

  1. In 2nd example, there is localStorage(similarly i can use AsyncStorage), but this is not good practice. Im think about, if there's any possibility to do something like redux-offline but based on react hooks without redux.

  2. New one

Actually, i need this feature to save my incomplete requests because of bad internet, so i could send them later.

dai-shi commented 4 years ago

2.

I see.

1.

Could you elaborate what is not good practice and how redux-offline works for it?

Thanks. I think this would be a good discussion to come up with an idea / a suggestion.

Temirtator commented 4 years ago

@dai-shi There is case, when i need to save many files, at least 200 or 300 files. The read/write operations are quite slow compared to any other storage systems. AsyncStorage doesn’t offer any offline Capability unless you bind it with another full-scale database like SQLite, or Realm. https://www.simform.com/react-native-database-selection-guide/#5

Also, found out that redux-offline uses, redux-persist library, and redux-persist library uses AsyncStorage for persistence of data on RN.

So, im decided to use one of the databases for my requests.

Temirtator commented 4 years ago

@dai-shi Maybe, u can bind library with sqlite database for persistence of data?

For example, create saveRequest(key, value) method, where value is some object which contain props like params, methodType, headers, and so on.

And all operations will be working with sqlite database.

dai-shi commented 4 years ago

saving to database asynchronously would be relatively easy.

const container = createGlobalState(...);

const setGlobalState = async (key, value) => {
  container.setGobalState(key, value);
  await saveToDatabase(key, container.getGlobalState(key));
};

const useGlobalState = (key) => {
  const [value, setValue] = container.useGlobalState(key);
  const setValueAndSave = useCallback(async (newValue) => {
    setValue(newValue);
    await saveToDatabase(key, container.getGlobalState(key));
  }, [setValue]);
  return [value, setValueAndSave];
};

export { setGlobalState, useGlobalState };

One caveat is saving the data from somewhere else will lead inconsistency.

Temirtator commented 4 years ago

Hello @dai-shi , i found out problem with getting saved data

const initialStringFromStorage = AsyncStorage.getItem(persistenceKey) => returns Promise
const initialState = initialStringFromStorage === null
    ? firstState
    : JSON.parse(initialStringFromStorage)

here's initialStringFromStorage is promise, not string

Temirtator commented 4 years ago

Also

const persistentReducer = (state, action) => {
    const mutated = myReducer(state, action)
    AsyncStorage.setItem(persistenceKey, JSON.stringify(mutated)) => should be asynchronously
    return mutated
}
dai-shi commented 4 years ago

AsyncStorage.setItem(persistenceKey, JSON.stringify(mutated)) => should be asynchronously

It's fine, unless you need to deal with possible errors.

here's initialStringFromStorage is promise, not string

Yeah, you can't take the same approach for async. What I would imagine is something like this.

const initialState = { ... }; // some initial values until hydration is finished

AsyncStorage.getItem(persistenceKey).then((loadedState) => {
  Object.keys(loadedState).forEach((key) => {
    setGlobalState(key, loadedState[key]);
  });
});

BTW, in v2, we will provide a new API which doesn't require the forEach above.

Temirtator commented 4 years ago

AsyncStorage.setItem(persistenceKey, JSON.stringify(mutated)) => should be asynchronously

It's fine, unless you need to deal with possible errors.

here's initialStringFromStorage is promise, not string

Yeah, you can't take the same approach for async. What I would imagine is something like this.

const initialState = { ... }; // some initial values until hydration is finished

AsyncStorage.getItem(persistenceKey).then((loadedState) => {
  Object.keys(loadedState).forEach((key) => {
    setGlobalState(key, loadedState[key]);
  });
});

BTW, in v2, we will provide a new API which doesn't require the forEach above.

thanks for answer, new feature would be nice

dai-shi commented 2 years ago

v2 is released and closing this.