optimizely / fullstack-labs

Apache License 2.0
13 stars 8 forks source link

Will it support react native? (LocalStorage not defined) #23

Open nielskrijger opened 5 years ago

nielskrijger commented 5 years ago

I was wondering if this library will support react-native in the future. I gave it a quick test and it threw the following error:

[OPTIMIZELY] - ERROR 2019-07-05T13:11:19.661Z EventProcessor: localStorage is not defined
asaschachar commented 5 years ago

Hi @nielskrijger, although we don't officially support React Native yet, the latest beta SDK version (0.3.0-beta1) can be made compatible with React Native.

First, ensure you are using the beta version of the @optimizely/react-sdk by specifying the beta version:

Using Yarn:

yarn add @optimizely/react-sdk@0.3.0-beta1

Then, one other caveat of React Native is that anytime JavaScript calls console.error, React Native will generate an error page. The underlying Optimizely JavaScript SDK uses a try...catch around usage of localStorage and uses a console.error when localStorage is not defined. So although the SDK should work fine when localStorage is not available, an error is still shown in React Native. We can work around this error by providing our own customLogger to the SDK and replace any console.error with console.warn:

// Provide Custom Logger
setLogger({
  log: function(level, message) {
    var LOG_LEVEL = enums.LOG_LEVEL
    switch (level) {
      case LOG_LEVEL.DEBUG:
        console.log(message);
        break

      case LOG_LEVEL.INFO:
        console.info(message);
        break

      case LOG_LEVEL.WARNING:
        console.warn(message);
        break

      case LOG_LEVEL.ERROR:
        console.warn(message); // Note: Use console.warn instead of console.error
        break
    }
  }
});

See a full working example of the v0.3.0-beta1 react-sdk being used in React Native below:

import React, {Fragment} from 'react';
import { StyleSheet, View, Text } from 'react-native';

import {
  createInstance,
  OptimizelyProvider,
  OptimizelyFeature,
  enums,
  setLogger,
} from '@optimizely/react-sdk'

// Provide Custom Logger
setLogger({
  log: function(level, message) {
    var LOG_LEVEL = enums.LOG_LEVEL
    switch (level) {
      case LOG_LEVEL.DEBUG:
        console.log(message);
        break

      case LOG_LEVEL.INFO:
        console.info(message);
        break

      case LOG_LEVEL.WARNING:
        console.warn(message);
        break

      case LOG_LEVEL.ERROR:
        console.warn(message); // Note: Use console.warn instead of console.error
        break
    }
  }
});

const optimizely = createInstance({
  sdkKey: 'CioLPpsSREvaDTzRDVAUpQ',
})

const App = () => {
  return (
    <OptimizelyProvider
      optimizely={optimizely}
      user={{
        id: 'user123',
        attributes: {
          'customerId': 123,
          'isVip': true,
        }
      }}
    >
      <View style={styles.center}>
        <Text>Example Application</Text>
        <OptimizelyFeature feature="hello_world">
          {(isEnabled) => (
            isEnabled
            ? (<Text> You got the hello_world feature! </Text>)
            : (<Text> You did not get the feature </Text>)
          )}
        </OptimizelyFeature>
      </View>
    </OptimizelyProvider>
  );
};

const styles = StyleSheet.create({
  center: {
    height: '100%',
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default App;

You can also see this example running in this Expo Snack

Since there are improvements we can make on our side to make this easier, the beta sdk needs to be released, and the docs need to be updated, I'll be leaving this issue open and will respond once there are better instructions. Hope this helps!