Horizon: [React Native] Add support for AsyncStorage

Created on 30 Aug 2016  路  1Comment  路  Source: rethinkdb/horizon

Server version: 2.0.0
Client version: 2.0.0

React Native's version of localstorage is AsyncStorage, it would be great if it was supported out of the box. I spent some time trying to add it to getStorage() but I eventually ran out of time and found a possible workaround that I could do in my app code instead. My findings/potential challenges:

  1. AsyncStorage has the same method names for setting/getting (getItem, etc) as localstorage, which is good, but it is async (no shit Sherlock!) and returns a promise. So it can't be called the same way as localstorage. To unify access to all storages, the localhost and FakeStorage method return values should probably be resolved into promises as well.
  2. AsyncStorage is part of react-native npm package, which is quite big. It would be nice if horizon didn't have to explicitly depend on react-native but just use AsyncStorage if the main app has it installed, but not 100% sure how to do that.

The following app code relies on the FakeStorage mechanism in Horizon and uses AsyncStorage to persist the storage in the app.

Btw. Horizon.clearAuthTokens() does not seem to work (see code comment below), not sure if it is broken with FakeStorage or if it's something with RN.

import React, { Component } from 'react';
import { AsyncStorage } from 'react-native';
import Horizon from '@horizon/client';

const horizonOptions = {
  host: 'localhost:8181',
};

let horizon;

export class Machine extends Component {
  state = {
    currentUser: null,
    authEndpoint: '',
  };

  signOut = () => {
    AsyncStorage.removeItem('horizon-jwt').then(() => {
      // Horizon.clearAuthTokens(); is not working in RN so using connect
      // without token to get the same behavior.
      this.connect();
    });
  }

  signIn = (horizonToken) => {
    if (! horizonToken || this.state.currentUser) {
      return;
    }

    AsyncStorage.setItem('horizon-jwt', horizonToken);
    this.connect(horizonToken);
  };

  // Custom methods
  connect(horizonToken = undefined) {
    // Options
    let options = Object.assign({}, horizonOptions);
    if (horizonToken) {
      options.authType = {'token': horizonToken};
    }

    horizon = Horizon(options);

    horizon.status(e => {
      console.log('status', e);
    });

    horizon.onSocketError(e => {
      console.log('socketError', e);
    });

    // Get the OAuth endpoint
    horizon.authEndpoint('auth0').subscribe(endpoint => {
      this.setState({authEndpoint: endpoint});
    });

    // Check if user is logged in
    if (horizon.hasAuthToken()) {
      horizon.currentUser().fetch().subscribe(user => {
        this.setState({currentUser: user});
      });
    } else {
      this.setState({currentUser: null});
    }
  }

  // Lifecycle methods
  componentDidMount() {
    AsyncStorage.getItem('horizon-jwt').then(horizonToken => {
      this.connect(horizonToken);
    });
  }

  render() {
    return; //
  }
}

Most helpful comment

This is a good idea, I wonder if we can do it in a point release since it's an interface change (but not likely one people use).

I am hoping to make 2.1 a "react-native works" release

>All comments

This is a good idea, I wonder if we can do it in a point release since it's an interface change (but not likely one people use).

I am hoping to make 2.1 a "react-native works" release

Was this page helpful?
0 / 5 - 0 ratings

Related issues

danielmewes picture danielmewes  路  7Comments

dalanmiller picture dalanmiller  路  7Comments

deontologician picture deontologician  路  3Comments

arthurvi picture arthurvi  路  7Comments

ChrisCates picture ChrisCates  路  3Comments