Search code examples
javascriptreactjsflowtypesetstate

Calling `this.setState()` breaks flow type checking on a prop in componentWillReceiveProps


I am getting a flow error on a prop that I know is a string when I call this.setState() right before it. If I move the setState() call after the line that uses the prop, the error goes away. The error I'm getting is:

null

This type is incompatible with the expected param type of string

undefined

This type is incompatible with the expected param type of string

Both errors occur on the same line of code.

Here is a stripped down version of the component. See the implementation of componentWillReceiveProps:

import React, { Component } from "react";
import apiRequest from "../../services/apiRequest";

type PropsT = {
  endpoint: ?string,
};

export default class ApiLoader extends Component {
  props: PropsT

  static defaultProps = { endpoint: null }
  state = { isFetching: true }

  componentWillReceiveProps(nextProps: PropsT) {
    if (!nextProps.endpoint) return;

    this.setState({ isFetching: true });
    this.fetch(nextProps.endpoint);       // FLOW ERROR HERE
  }

  fetch(endpoint: string) {
    apiRequest.get(endpoint)
      .then(() => this.setState({ isFetching: false }));
  }

  render(): React.Element<*> {
    return <div>Whatever.</div>;
  }
}

Simply switching the order of those final two lines in componentWillReceiveProps fixes it:

this.fetch(nextProps.endpoint);      // NO ERROR!
this.setState({ isFetching: true });

Is this just a bug in Flow, or am I missing something?


Solution

  • This is due to a type refinement invalidation: https://flow.org/en/docs/lang/refinements/#toc-refinement-invalidations

    Pull out endpoint into its own variable and you should be good to go.