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

Designing and maintaining an open-source React Native library

Designing and maintaining an open-source React Native library

Be03847a223c7afbad30c4993ea61a6e?s=128

Mathieu Acthernoene

October 14, 2021
Tweet

More Decks by Mathieu Acthernoene

Other Decks in Technology

Transcript

  1. Designing and maintaining an open-source React Native library React &

    React Native Bordeaux
  2. Mathieu Acthernoene Lead front-end developer @ Swan Podcast host @

    Putain de Code !
  3. Maintainer of: react-native-bootsplash, react-native-localize, react-native-permissions

  4. React Native isn't magical 🧙

  5. React Native isn't magical 🧙 …The cost of cross-platform in

    react-native-localize
  6. None
  7. What's the bridge for? Reading sync data using constants, Calling

    async methods using promises or callbacks, Receiving events using event listeners
  8. What's the bridge for? Reading sync data using constants, Calling

    async methods using promises or callbacks, Receiving events using event listeners
  9. - (NSDictionary *)constantsToExport { return @{ @"initialTimeZone": [[NSTimeZone localTimeZone] name],

    }; } Objective-C TypeScript import { NativeModules } from "react-native"; const NativeModule: Readonly<{ initialTimeZone: string; }> = NativeModules.RNModuleTemplate; export const initialTimeZone = NativeModule.initialTimeZone;
  10. @Override public @Nullable Map<String, Object> getConstants() { HashMap<String, Object> constants

    = new HashMap<>(); constants.put("initialTimeZone", TimeZone.getDefault().getID()); return constants; } Java TypeScript import { NativeModules } from "react-native"; const NativeModule: Readonly<{ initialTimeZone: string; }> = NativeModules.RNModuleTemplate; export const initialTimeZone = NativeModule.initialTimeZone;
  11. What's the bridge for? Reading sync data using constants, Calling

    async methods using promises or callbacks, Receiving events using event listeners
  12. RCT_EXPORT_METHOD( getTimeZone:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject ) { @try { resolve([[NSTimeZone localTimeZone] name]);

    } @catch (NSException *exception) { reject(@"error_code", exception.reason, nil); } } import { NativeModules } from "react-native"; const NativeModule: Readonly<{ getTimeZone: () = > Promise<string>; }> = NativeModules.RNModuleTemplate; export function getTimeZone(): Promise<string> { return NativeModule.getTimeZone(); } Objective-C TypeScript
  13. None
  14. @ReactMethod public void getTimeZone(Promise promise) { try { promise.resolve(TimeZone.getDefault().getID()); }

    catch (Exception exception) { promise.reject("error_code", exception.getMessage()); } } Java import { NativeModules } from "react-native"; const NativeModule: Readonly<{ getTimeZone: () = > Promise<string>; }> = NativeModules.RNModuleTemplate; export function getTimeZone(): Promise<string> { return NativeModule.getTimeZone(); } TypeScript
  15. None
  16. What's the bridge for? Reading sync data using constants, Calling

    async methods using promises or callbacks, Receiving events using event listeners
  17. - (void)startObserving { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onTimeZoneChange) name:NSSystemTimeZoneDidChangeNotification object:nil]; }

    - (void)stopObserving { [[NSNotificationCenter defaultCenter] removeObserver:self name:NSSystemTimeZoneDidChangeNotification object:nil]; } - (NSArray<NSString * > *)supportedEvents { return @[@"timeZoneChange"]; } - (void)onTimeZoneChange { [self sendEventWithName:@"timeZoneChange" body:@{ @"date": [[NSISO8601DateFormatter new] stringFromDate:[NSDate date]], @"value": [[NSTimeZone localTimeZone] name], }]; } Objective-C import { NativeEventEmitter, NativeModules } from "react-native"; const emitter = new NativeEventEmitter(NativeModules.RNModuleTemplate); type Listeners = { timeZoneChange: (body: { date: string; value: string }) = > void; }; export function addListener<Type extends keyof Listeners>( type: Type, listener: Listeners[Type], ): () = > void { const subscription = emitter.addListener(type, listener); return subscription.remove; } TypeScript
  18. WritableMap body = Arguments.createMap(); DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());

    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); body.putString("date", dateFormat.format(new Date())); body.putString("value", TimeZone.getDefault().getID()); getReactApplicationContext() .getJSModule(RCTDeviceEventEmitter.class) .emit("timeZoneChange", body); import { NativeEventEmitter, NativeModules } from "react-native"; const emitter = new NativeEventEmitter(NativeModules.RNModuleTemplate); type Listeners = { timeZoneChange: (body: { date: string; value: string }) = > void; }; export function addListener<Type extends keyof Listeners>( type: Type, listener: Listeners[Type], ): () = > void { const subscription = emitter.addListener(type, listener); return subscription.remove; } Java TypeScript
  19. How to organize your module repository

  20. Sources github.com/zoontek/react-native-module-template - or - github.com/callstack/react-native-builder-bob

  21. PUBLISH

  22. That was the first 20% of the work

  23. None
  24. None
  25. None
  26. ( This one is a joke) ( It still triggered

    me)
  27. Huge projects depend on single-maintainer dependencies

  28. None
  29. None
  30. Preserve yourself

  31. None
  32. My tricks to avoid open-source burnout 😌

  33. None
  34. None
  35. None
  36. None
  37. How it was done before github issue forms

  38. Don't feel bad for not dealing with everything

  39. None
  40. None
  41. None
  42. A friend 👉 Also a friend 👉 Also a friend

    👉
  43. Don't do it for money 💸

  44. Know what you want to maintain Why not a PHILOSOPHY

    ( .md)? You think it belongs to module core You think it doesn't Consider the PR Feel free to refuse (and explain nicely why)
  45. Know what you want to maintain Especially in the React

    Native environment
  46. Think about: React Native updates and breaking changes iOS updates

    and breaking changes Android updates and breaking changes macOS updates and breaking changes Windows updates and breaking changes RNW updates and breaking changes React updates and breaking changes …
  47. None
  48. None
  49. Focus on one thing Let people create their own abstractions

    in user-land
  50. Embrace help 🤝 Even if they don't know the tech,

    people can help you (triage, linking to similar issues, asking for more details, etc.)
  51. 🙇 Thank you! Questions? Mathieu Acthernoene Lead front-end developer @

    Swan Podcast host @ Putain de Code !
  52. Sources: - https://formidable.com/blog/2019/react-codegen-part-1 - https://mikemcquaid.com/2018/03/19/open-source-maintainers-owe-you-nothing/ - https://github.com/facebook/react-native/issues/23313 - https://github.com/doczjs/docz/issues/1634