Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@xavierartot
Created September 17, 2018 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xavierartot/14db0e979882c513014ac2fd58ad1ab7 to your computer and use it in GitHub Desktop.
Save xavierartot/14db0e979882c513014ac2fd58ad1ab7 to your computer and use it in GitHub Desktop.
Things I learned the hard way using React Native

Things I learned the hard way using React Native

Set up your environment carefully: It's important to have one canonical source of truth per environment, per platform. (i.e. iOS Development, iOS Testflight, iOS Production, ditto Android.) Every time you build, your config should propagate values from one input source (per platform) to either Java/JavaScript or Objective-C/JavaScript. Here's what we did for Android and here's what we did for iOS. I don't doubt that you can do better. Please do better. But you can't say that we didn't have one canonical source of truth that worked very simply and effectively throughout the development process.

Don't wait until the end to develop Android and iOS concurrently: Even if you're not actively focusing on both platforms, don't assume that "RN is cross platform… we can develop iOS and flip the Android switch when we're done." It's mostly cross-platform. But there's lots of little stuff like iOS and Android handling margins on text differently. Small quirks, but not the sort of stuff you want to completely refactor at the end.

Use a linter: I like semistandard. We ran into lots of frustrating issues where we had duplicate keys in hashes that didn't fail until we moved to the web platform. A linter can be annoying, but it's not so bad if you get on board early. Prevents you from doing lots of stupid invalid stuff that doesn't actually cause errors.

Learning Redux: It was useful to read the source itself. It's actually relatively concise. It helped clear up my understanding of what's going on. Understanding exactly why components get updated is key to accomplishing reasonable performance. I think this is the line that does it in redux. We debated whether to connect giant parts of the state tree or lots of little values. Also whether to connect tonnnns of little components or just the big components. Short answer: understand why things get re-rendered and a happy medium is probably best because both extremes have tradeoffs. Seems sketchy to connect everything but then it's overkill and unnecessarily verbose to unpack tons of values in every mapStateToProps. Happy medium, I think.

But what's the right data store??? The right data store is one that you understand. We stored our stuff in some weird key-value store (okay, a glorified plain old javascript object). It worked pretty well, but what would have made it better would have been either to understand what triggers updates better from the start or maybe to take the plunge and get on board with immutablejs from the start. But there's no one true answer. If you use a library for your datastore, try to understand why it does what it does (which doesn't necessarily include worrying about the internal workings).

Put console.logs in your render statements and figure out just how often things are getting rendered. You can get away with a lot for a while using react. The second major release of our iOS app was mainly a giant audit of why there was so much extra rendering going on. Performance increased dramatically.

Follow people on twitter @dan_abramov, @JI, @ReactJSNews, @Vjeux. Lots more. A good way to be a fly on the wall and find out about trendy stuff without getting sucked into too deep of a rabbit hole.

React universal template (web, app, server): https://github.com/este/este

My template which has maybe a couple things going for it regarding redux setup (immutable part could be edited out): https://github.com/rreusser/react-native-with-everything

This guy’s stuff is outstanding:

Corollary: icomoon.io is the best thing ever for managing icons.

Keyboard spacer: I highly recommend a single keyboard spacer at the bottom of your top-level view. Or at least very few as high up in the DOM as possible. No need to add them all over the place (it's a mess), and best to avoid fixing the height of anything to the height of the viewport (Android and the in-call status bar will make your life unpleasant). https://www.npmjs.com/package/react-native-keyboard-spacer

Higher order components (enhancing behavior without mixins or class inheritance): https://gist.github.com/sebmarkbage/ef0bf1f338a7182b6775

This is useful. Premature optimization is bad, but good to get a handle on what optimization means: https://github.com/garbles/why-did-you-update

Stateless functional components: https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html#stateless-functional-components Good for components that can have no internal state.

var Button = (props) => {
  return <View><Text>{props.label}</Text></View>
}

But be careful with those because: An interesting discussion on avoid re-rendering the entire app on every state update: https://medium.com/@esamatti/react-js-pure-render-performance-anti-pattern-fb88c101332f#.u3tqgdf47

Or just forget understanding optimization and use this: 😄

A trivial optimization that may actually (surprisingly?) be noticable: Instead of this:

return <Touchable onPress={() => { do something inline}}/>

Do this:

_onPress = () => {
  same thing but not inline
};

render () {
  return <Touchable onPress={this._handlePress}/>
}

For events like keypresses, the recreation of an unoptimized callback over and over and over actually seems to noticably slow down the UI. Who would have guessed?

Fun facts:

You can always return/insert an array of keyed nodes instead of jamming everything together (note to self: the actual return value of render needs to be a single node though, right?)

renderSomePart = () => {
  return [
    <View key="item-1"/>,
    <View key="item-2"/>
  ];
};

OR:

renderItem = (item, i) => (
  <View key=`item-${i}`> ... </View>
)

renderSomePart = () => {
  return this.props.someDataItems.map(this.renderItem);
};

And text nodes can contain other text nodes. Our first attempt was to split text by whitespace and lay out nodes with flexbox. That was crazy. You can just nest text nodes and make some of them pressable. Sounds obscure, but it wasn't obvious and if you need it, it's life-changing.

render () {
  return <View>{[
    <Text key="1">Hello, </Text>,
    <Text key="2">{[
      <Text key="1" onPress={...}>this is a link</Text>,
      <Text key="2">, and this is just regular text</Text>
    ]}</Text>
  ]}</View>;
}

Random fact: margins and padding on text elements more or less doesn't work on android, so really try to avoid them!

How to add a loading overlay. Absolutely position the overlay top/right/left/bottom: 0 and make sure it’s after the rest of the content it needs to overlay. Draw order is last-on-top:

<View>
  <……>
  <LoadingOverlay>
</View>

Android installation (Genymotion)

This is for Genymotion setup. I think Android Studio 2.0 is maybe better now. In particular, I got confused about which android sdk directory things were pointed at, so however you install android stuff, take note of that.

  1. Install android sdk via homebrew. brew install android-sdk
  2. Download and install VirtualBox
  3. Run $ android and install lots of SDKs... Google Play + Google Repositories under Extras, in particular...
  4. Install genymotion
  5. In the genymotion settings tab, go to ADB and enter /usr/local/Cellar/android-sdk/24.4.1 (or similar, depending on what homebrew installed. Maybe .../24.1.1/bin?)
  6. Run $ANDROID_HOME/bin/android and select "Google Repository", amonng maybe a few other things that look reasonable
  7. Start your device! woot.
  • Install Google Play Serivces
  • Drag ARM_Translation_something_or_other.zip onto the simulator, flash, quit, and restart (note: you’ll have to find this on a MEGAFREEDOWNLOADS.COM sort of site. Try to avoid malware. It’s crazy. Come on, Android. The gist below is a good place to find it.)
  • Ditto for gapps zip file
  • Restart the simulator
  • At this point you should get a message that says google play has stopped working 👍
  • Go to Play Store and sign in.
  • Click the hamburger menu, go to My Apps, and update all
  • If that doesn't work, check at: https://gist.github.com/wbroek/9321145
  1. BAM.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment