Using React(Native) + MobX + Flow, Flow treats @inject as error

acro5piano

Kay Gosho

Posted on April 10, 2018

Using React(Native) + MobX + Flow, Flow treats @inject as error

This is a story for flow, who doesn't understand ESNext Decorator.

Overview

Flow, who checks static type of JS(X), does not understand Decorator of ES Proposal (Stage 1, 2018/04/11).

At first, Flow does not pass if we use Decorators (like @inject).
We should add the following configuration to .flowconfig to execute flow check with Decorators.

esproposal.decorators=ignore
Enter fullscreen mode Exit fullscreen mode

However, this let flow ignore Decorators so he does not interpret them.
Thus, he claims errors if we use @inject to inject MobX's store in React components.

To handle this error, the only one choice is not to use Decorators.

Another possible choice is to defaultProps as this article, suggests,

https://wietse.loves.engineering/using-flowtype-with-decorators-in-react-af4fe69e66d6

but I think we should avoid that kind of HACK because it increases undesirable types, and we cannot trust Props anymore.

Prerequisite

  • Developing with React(Native) + MobX + Flow
  • Installed babel-plugin-transform-decorators-legacy
  • Not select the easiest way using Component<*> or $flowFixMe

Problem

When @inject cause errors,

// App.jsx

// @flow

import { React, Component } from 'react'
import SomeComponent from './SomeComponent'
import Stores from './stores'

const stores = new Stores()

class App extends Component<{}> {
  render() {
    return (
      <Provider stores={stores}>
        <ScrollView>
          <SomeComponent someProperty="Hello" />
        </ScrollView>
      </Provider>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode
// SomeComponent.jsx

// @flow

import { React, Component } from 'react'
import SomeStore from './stores/SomeStore'

type Props = {
  someStore: SomeStore<*>;
  someProperty: string;
}

@inject('someStore')
@observer
export default class SomeComponent extends Component<Props> {
  render() {
    const { someProperty, someValue } = this.props.someStore

    return ( 
      <Text>{someProperty}, {someValue}</Text>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

When we run flow check in our console, Flow creates the following error:

Property `someStore` is incompatible:

# ...

property `someStore`. Property not found in. see `SomeComponents.js`

# ...

props of React element `SomeComponent`
Enter fullscreen mode Exit fullscreen mode

Let me describe how Flow feels.
He ignores Decorators so he doesn't understand Decorators.
Flow is nice guy, so he are focusing what he should do.

But we would like to use Decorators regardless to his policy.

Solution

Really simple, as if I don't have to write this article.

We should give up to use @inject until Flow supports it. Instead, we use inject as a normal JavaScript function.
I think this does not influent code readability.

// SomeComponent.js (part)

@observer
class SomeComponent extends Component<Props> {
  render() {
    const { someProperty, someValue } = this.props.someStore

    return ( 
      <Text>{someProperty}, {someValue}</Text>
    )
  }
}

export default inject('someStore')(SomeComponent)
Enter fullscreen mode Exit fullscreen mode

Very simple solution, but for ES beginner it took much time to hit this solution.

Hope this article helps you.

Refs

https://gist.github.com/vonovak/29c972c6aa9efbb7d63a6853d021fba9

💖 💪 🙅 🚩
acro5piano
Kay Gosho

Posted on April 10, 2018

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related