What is the proper way to use React Memo with Flow?

Viewed 4433

This line of code

export default memo(LoadingOverlay);

Gives flow error

Missing type annotation for `P`. `P` is a type parameter declared in  function type [1] and was implicitly instantiated at  call of `memo` [2].Flow(InferError)

And this line

export default memo<TProps>(LoadingOverlay);

Gives compile time error. What's the proper use of React memo with flow?

EDIT:

Here is the full file example

// @flow

// React modules
import React, { memo } from 'react';

// Material UI components
import Checkbox from '@material-ui/core/Checkbox';
import FormControlLabel from '@material-ui/core/FormControlLabel';

// Utils and defaults
import './checkbox.scss';

type TProps = {
  value: string;
  label: string;
  checked: boolean;
  disabled?: boolean;
  onChange: Function;
};

/*
 * Presentational component with following props:
 *  value: String, value as a name of checkbox
 *  label: String, checkbox label
 *  checked: Boolean, checkbox state
 *  disabled: Boolean, checkbox availability state
 */
const Checkbox = (props: TProps) => {
  console.log('RENDER CHECKBOX');
  const {
    value,
    label,
    checked,
    disabled
  } = props;
  const { onChange } = props;

  return (
    <FormControlLabel
      control={
        <Checkbox
          checked={checked}
          onChange={onChange(value)}
          value={value}
          disabled={disabled}
          color="primary"
        />
      }
      label={label}
    />
  );
};

Checkbox.defaultProps = {
  disabled: false,
};

export default memo<TProps>(Checkbox);
2 Answers

I have got the same problem. The problem is not with the Flow but with Babel.

React.memo with Flow

You have got it right. Correct approach really is:

export default memo<Props>(MyComponent);

Compilation problem

There are two ways to solve that.

1. Simple: Adding flow annotation to the top

Add // @flow to the top of the file. The error comes from Babel and it needs the annotation there. Even though you might have all=true in .flowconfig (and Flow work perfectly) you need to do that.

Useful when using create-react-app and do not want to eject.

2. Configuring Babel

Add Babel preset for Flow and specify "all": true option to your .babelrc:

{   
  "presets": [
    ["@babel/preset-flow", {
      "all": true
    }]
  ]
}

However, this needs anyone using create-react-app to eject. (Or might use react-app-rewired but I have no experience with that.)

This solution is mentioned on here (thanks @fl0shizzle for mentioning it) and for discussion about create-react-app solution look on here.

Make sure you have the latest version of flow. When I updated my flow version it just worked. I was missing the // @flow at the top so had to add all=true to my preset config.

Related