Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Offline First React Native

Offline First React Native

In this talk, we'll take a look at why offline first matters and go deep on some strategies to help you build the performant offline first mobile apps.

Bc3e5951a9e5ec8f9f4546f2a0bc6192?s=128

Tim Whitacre

October 18, 2019
Tweet

Transcript

  1. O!ine First React Native Connect.Tech 2019

  2. Tim Whitacre Atlanta Engineering Manager @ New Story Charity ✨

    @timwco ✨ @newstorycharity
  3. We pioneer solutions to end global homelessness. newstorycharity.org

  4. O!ine First

  5. O!ine first is an approach to software development in which

    developers build an application's core features to function with or without an internet connection. ... This is especially important for end users who travel and experience internet coverage blind spots. 1 1 https://whatis.techtarget.com/definition/o"ine-first
  6. Why O!ine First » Connected & Powered => Disconnected &

    Battery » Geography plays an important role » O!ine is simply a fact of life. !
  7. Why Now? When else are you going to think about

    it?
  8. Benefits » Avoid Local Data Loss » Speed Up Your

    App » Your App Runs Everywhere
  9. Pitfalls » Data Conflicts » Diverse Data Types » Implementation

    Time » Others 2 2 https://alistapart.com/article/o"ine-first
  10. O!ine Syncing Options » Real Time » Data Syncs Upon

    Connection » Progressive Enhancement » Manual » Manually preform a sync operation » Architecture Strategy
  11. O!ine first requires a mix of UX and Development Strategies.

    This includes both frontend and backend solutions.
  12. Please don't skip the UX part.

  13. How Do O!ine Apps Work?

  14. Local Storage !

  15. { org_1234: { app_status: { last_upload: '2019-09-03T20:59:05+00:00' }, admin_user: {

    name: 'Stacy', token: 'ABCDEF123456' }, data: { ... } }, org_5678: { app_status: { last_upload: '2019-10-17T21:33:01+00:00' }, admin_user: { name: 'Ikenna', token: 'HIJKLMNO789' }, data: { ... } } } See a potential problem...?
  16. O!ine Tools » GraphQL » Redux O!ine/Persist » Realm

  17. GraphQL Only get the data that we need. Less queries,

    less operations and quicker access to data.
  18. export const SYNC_DOWNLOAD = gql` query Download($lastSyncedAt: ISO8601DateTime) { posts(lastSyncedAt:

    $lastSyncedAt) { id title content comments { id content } } authors(lastSyncedAt: $lastSyncedAt) { id first_name last_name } categories(lastSyncedAt: $lastSyncedAt) { id title } } `;
  19. Redux O!ine/Persist Redux O!ine allows us to store and "rehydrate"

    our state as needed.
  20. // Store Configure import { createStore, applyMiddleware, compose } from

    'redux'; import { persistStore, persistReducer } from 'redux-persist'; import storage from 'redux-persist/lib/storage'; import { createOffline } from '@redux-offline/redux-offline'; import offlineConfig from '@redux-offline/redux-offline/lib/defaults'; import reducers from './reducers'; const { middleware, enhanceReducer, enhanceStore } = createOffline({ ...offlineConfig, persist: false }); export default key => { const persistConfig = { key, storage, blacklist: ['offline', 'user'] }; const persistedReducer = persistReducer(persistConfig, enhanceReducer(reducers)); const store = createStore( persistedReducer, compose( enhanceStore, applyMiddleware(middleware))); const persistor = persistStore(store); return { store, persistor }; };
  21. // App.js import { Provider as ReduxProvider } from 'react-redux';

    import { PersistGate } from 'redux-persist/integration/react'; import configureStore from 'utilities/configure-store'; class App extends Component { render () { const orgId = getOrganizationId(); const { store, persistor } = configureStore(orgId); return ( <ReduxProvider store={store}> // Standard Redux Provider <PersistGate persistor={persistor}> // Delays rendering of app <MainAppNavigation /> </PersistGate> </ReduxProvider> ); } }
  22. Realm Realm Database is a fast, easy to use, and

    open source alternative to SQLite and Core Data. » Mobile First » Simple API, Define Schemas » Faster than SQLite » Lazy Queries » Data Migrations !
  23. // Realm Models // models.js const PostSchema = { name:

    'Post', properties: { title: 'string', content: 'string', comments: 'Comment[]', tags: 'Tag[]', categories: 'Category[]', author: 'Author', } }; const CommentSchema = { name: 'Comment', properties: { author: 'Author', comment: 'string', approved: 'bool' } }; // Tag Schema // Author Schema // Category Schema
  24. // Realm Setup // realm-setup.js import models from './db/models'; //

    { Posts, Comments, Tags, Categories } const database = async (orgId, schemaVersion) => { if (orgId === 'guest') return null; // If no user, no need for a database const schema = Object.values(models); const config = { schema, path: `${orgId}.realm`, schemaVersion }; return await Realm.open(config); };
  25. // App.js import realmSetup from 'utilities/realm-setup'; // Import Realm class

    App extends Component { render () { const schemaVersion = 1; const orgId = getOrganizationId(); const realm = realmSetup(orgId, schemaVersion); return ( <ReduxProvider store={store}> <PersistGate persistor={persistor}> <MainAppNavigation screenProps={{ realm }} /> </PersistGate> </ReduxProvider> ); } }
  26. Realm Queries // Basic Query const posts = realm.objects('Post'); posts.forEach(p

    => console.log(p.title)); // Posts Sorted Alphabetically const sortedPosts = posts.sorted('title'); // Specific Query (Comments Are Approved) const comments = realm.objects('Comment'); const posts_comments = comments.filtered('approved = true');
  27. Realm Writes // New Comment const author = realm.objectForPrimaryKey('Author', 1);

    const newComment = { author, comment: 'Offline is really cool' }; // Create On it's Own realm.write(() => realm.create('Comment', newComment)); // Create with Relationship const post = realm.objectForPrimaryKey('Post', 291); try { realm.write(() => { post.comments.push(newComment)}); } catch (e) { console.log('Error Upon Creation'); }
  28. Pitfalls » Maintenance (Active Development) » Dependency & Upgrades

  29. Review » UX/UI Strategy » Local Data Loss (Realm) »

    Global State Persistence (Redux O!ine/Persist) » Diverse Data Types (Realm, GraphQL) » Data Conflicts (Realm, GraphQL)
  30. Thank You ! l.timw.co/ctech2019 ✨ @timwco ✨ @newstorycharity

  31. Image Credits » Devopedia » @andreee » New Story Charity