bcherny / undux

⚡️ Dead simple state for React. Now with Hooks support.

Home Page:https://undux.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Usage with React Native AsyncStorage

matheusgrieger opened this issue · comments

I'm trying to save the store data to the AsyncStorage of my React Native application. Currently, it works well for store -> AsyncStorage data flow, since it's a simple Undux effect.

But how about loading data from the AsyncStorage and getting it back to the store? Is there an "on created" event that I can listen to, or something like that?

Haven't found anything similar in the docs. Thank you!

Hey @matheusgrieger! Can you explain a bit more what you mean by "loading data from the AsyncStorage and getting it back to the store" -- do you mean you want to update your Undux store any time AsyncStorage updates?

If so, we do something similar for the Undux doc site, to sync state to the URL and back. See https://github.com/bcherny/undux.org/blob/a4dc3180587688e4fec3abffbb90b1d3fe600470/src/services/hashSync.ts.

Does that help?

What I mean is, whenever I open my React Native app, I want to fetch all data from AsyncStorage and store them in Undux. From Undux to AsyncStorage is a straightforward and simple approach.

Since AsyncStorage, as the name itself implies, loads data asynchronously, I have to wait some promises to resolve before creating the store.

So far I have solved it by using a renderless component that does this job.

Thank you!

I see - there’s a few good ways to do that. Think you can give a code sample for what the initial data load from AsyncStorage looks like? The best approach depends on what exactly that API looks like.

It can be whatever we want: from individual key/value pairs, to a whole object with all the data. Here is the code running in my app right now:

export default Store.withStore(
  class StoreLoader extends React.Component {
    componentDidMount() {
      this.loadStoreData();
    }

    loadStoreData = async () => {
      const { store } = this.props;

      const promises = [
        AsyncStorage.getItem('user'),
        // there are a few others here that have been removed for brevity
      ];
      const [user] = await Promise.all(promises);

      // here there would be a call to .set() for every promise resolved
      // not ideal, but it's working
      store.set('user', user);

      this.onLoaded(store);
    };

    onLoaded = (store) => {
      const { onLoaded } = this.props;
      onLoaded(store);
    };

    render() {
      return null;
    }
  },
);

This component gets rendered when the application opens, before anything else.

Thanks for sharing your code! What you probably want to do here is instead of wrapping StoreLoader with withStore, update StoreLoader’s render method to:

return <Container initialState={{...initialStoreState, this.state.stateFromAsyncStorage}}>
{this.props.children}

Where initialStoreState is the initialState you defined for your Undux store, and stateFromAsyncStorage is the initial state you loaded from AsyncStorage.

Does that make sense? Pardon the formatting, I’m on my phone.

Hmm, that seems interesting. The way it works right now is that this StoreLoader component gets swapped by our AppNavigator once it finishes loading, but the Container stays still in place wrapping both components.

This approach is very interesting, indeed. Thank you!