You already know what it is. Tough times require tough measures, so here I am… locked inside my house for my own safety. So far I can not complain - I even picked up writing on this blog again, which seems like a pretty damn good idea if you ask me. Hold up - before you get all judgemental and start throwing shade at me for being absent, I just want to let you know that I’ve been working on a new project since January. Needless to say, I dedicated all my free time to it, hence I had no chance to keep this blog going. Yeah, I’ve been working on the weekends like usual… and yeah, I’ve just quoted Drake - you mad? I guess at this point I should create a Spotify playlist for you all. At least this way, my diary will have a cool soundtrack, and maybe…just maybe, it will inspire some of you to stop procrastinating and get some shit done.
I’m already running a little behind schedule, so I’ll just go do my workout routine. Afterwards, we can talk about the app I’m working on and start dealing with some problems I’ve encountered lately. Till then, stay in shape!
One eternity later…
Breakfast ✅ Workout ✅ Shower ✅
Now coming back to our business - I’m proud to say that lately, I’ve been experimenting with React Native. This was something new to me and I have to admit: it’s been a challenging ride. At first, I thought: “Well, I know a bit of React and I guess could say that I already master the flexbox, so what can go wrong?“. Funny. Everything can go wrong, you dumbass.
First things first though - where do we start? I had no time for a crash course, so I looked for something that could have given me at least a faint idea about the structure of a native app. A good friend of mine, also a developer, told me about Expo, so I installed the CLI right away and proceeded to create my first project. Cool! So far we got the ‘Hello World’ screen in place. What next?
As I said, React was nothing new to me so I started coding immediately, thinking: “What can be so different about React Native?“. Well, nothing… except for lots of things. A couple of hours into it and I was already screaming at everybody in the room. I literally googled ‘How the hell are you supposed to write CSS in React Native?‘. Imagine! Like literally, take a moment and picture this in your head.
I was about to give up and call it a day, but then this happened. As I was scrolling on Twitter, I found this interesting tweet of a teacher I had in college, in which he teased one of his upcoming projects, called Steal Like a Dev. In that very second, a good idea (finally a good one) occurred to me. Let’s just steal something… make like a clone of a well-known app. Luckily, one of my friends discovered this tutorial.
Guess what happened next… exactly - we started cloning the Airbnb app right away. With the help of Kriss (the author), we managed to get a good grip on the basics of React Native and create a couple of screens for our onboarding UX. We also managed to add the navigation(this was tricky) and lay down the boilerplate of our project. Next, we got our backend in place, using Grapcool and in almost no time, the login & authentication component was done. Afterwards, we opened the champagne and celebrated our first big achievements - which was cool, except that we didn’t have any champagne and we had to settle for a beer. Let’s just pretend it was champagne though, for the sake of this story and the dramatic effect.
Fast forward a couple of months, and everything seems to be coming to an end. Of course, there are still some things that I have to take care of, but I’m pretty happy with my progress. The problem that I’m willing to tackle today is “Data Persistence”. We’ve got the major flows running smoothly, but unfortunately, every time the user quits the app all the data is gone, and he has to go through the login process again when he comes back. We don’t want that, right? So let’s just deal with this issue.
Our redux store is already in place, so we need to find a way to store the data until the user comes back. I did my homework, so I’ll just go ahead and install a package called redux-persist.
Now let’s enhance our store. Open the App.js
file and add a PersistGate
as it follows:
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { AppRegistry } from 'react-native';
import { store, persistor } from './src/redux/index';
import { PersistGate } from 'redux-persist/integration/react';
import { ApolloClient } from 'apollo-client';
// other imports
// configuration of Apollo Client
class App extends Component {
render() {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<ApolloProvider client={client}>
<Root />
</ApolloProvider>
</PersistGate>
</Provider>
);
}
}
AppRegistry.registerComponent('App', () => App);
export default App;
Now that we did that, let’s take a look at our store configuration:
import React from 'react';
import { compose, createStore, applyMiddleware } from 'redux';
import { createLogger } from 'redux-logger';
import thunkMiddleware from 'redux-thunk';
import { connect } from 'react-redux';
import rootReducer from '../redux/reducers';
import { persistStore, persistReducer } from 'redux-persist';
import { AsyncStorage } from 'react-native';
const persistConfig = {
key: 'root',
// We will store everything inside the Async Storage
storage: AsyncStorage,
// Whitelist the reducers that you want to be persisted
whitelist: [
'AuthReducer'
],
// Just throw the things that you don't want to be persisted in here
blacklist: [
'Navigation'
],
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
/*
Add a logger middleware for the ease of debugging
I totally hate this about React Native
*/
const loggerMiddleware = createLogger({ predicate: () => __DEV__ });
const enhancer = compose(
applyMiddleware(
thunkMiddleware,
loggerMiddleware,
),
);
const store = createStore(persistedReducer, initialState, enhancer);
let persistor = persistStore(store);
export {
store,
persistor,
};
Pretty straight-forward, right? All we needed to do is add a persistConfig
to our rootReducer
to let him know which information should be stored until I come back. As you can see the result of this operation is a so-called persistedReducer
that will be further used when we create the store. We also specified that all this data should be saved in the Async Storage
which is an unencrypted, asynchronous, persistent, key-value storage system, global to the app. It comes together with react-native
, but bear in mind that this package is deprecated according to the official documentation. The recommendation is to use the react-native-community/react-native-async-storage instead. Quick heads up: if you’re using Expo like me, you won’t be able to enjoy the community version just yet, unless you eject the app. I highly doubt you want to do that, though. To wrap things up, I created a persistor based on our store, which will used by the PersistGate
in our App component presented above.
Cool, let’s look at our rootReducer
for a second.
import { combineReducers } from 'redux';
import * as Navigation from './navigation';
import * as AuthReducer from './userInfo';
export default combineReducers(Object.assign(
AuthReducer, // This one will be whitelisted
Navigation, // I really don't care about this one
));
No biggie. I bet you already got it. This being said… we’re ready to roll. Yeah, we’re magically done. But let’s see what happens under the hood. Persistence is usually achieved in 3 main steps: INIT, PERSIST and REHYDRATE. If I remember correctly, till the 5th version of the redux-persist
package you had to trigger the REHYDRATE action yourself, but it’s no longer the case. I would still like to go over every single step though, if you don’t mind.
INIT - the title is self-explanatory. At this stage, the Redux Store is instantiated as the initial state given through the reducers.
PERSIST - now we start saving objects in the store. You’ll notice that all the new items have a property version
set to -1
and a boolean called rehydrated
which is false
at this stage. The latter is used in order to check if the persistence has been applied yet.
REHYDRATE - where the magic happens. The persisted data in our Async Storage is now replacing the data in the Redux Store. Every reducer is basically “rehydrated” as their content is now replaced by the persisted one.
I feel like I’m missing something though… Oh, yeah! I totally forgot to mention that you can use this approach in the browser as well, within your regular web app. Moreover, with a little help from the Redux Developer Tools, you’ll be able to get a better picture of these actions, as they get triggered in front of you.
This being said, I hope that this little quarantine diary of mine will come in handy one day, or at least make you laugh and forget about the new coronavirus.
At this point, I think I completely lost it and started writing these paragraphs out of loneliness, but screw it - I ain’t stoping here. We have to get this app done one way or another.
See you tomorrow.
Subscribe to our newsletter and stay updated.