Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typing React components in Flow when passing a component as a prop

I want to pass a React component as input prop to another React component. I tried to reference it as React.Component<*, *, *> but when I use the passed component in the render method I get an error. This is how I wrote out my flow code.

/* @flow */

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

const Input = props => <div>Yo</div>

type DefaultProps = {
  InputComponent: Input
};

type Props = {
  InputComponent: React.Component<*, *, *>
};

class App extends Component<DefaultProps, Props, void> {
  static defaultProps = {
    InputComponent: Input
  };

  props: Props;

  render() {
    const { InputComponent } = this.props

    return (
      <div>
        <InputComponent />
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
)

However in the App render method I get the error

React element `InputComponent` (Expected React component instead of React$Component)

How should I properly type input components?

like image 282
Esben Avatar asked Apr 24 '17 08:04

Esben


People also ask

Can I pass props to styled component?

To pass props to React components created with styled-components, we can interpolate functions into the string that creates the component. We create the ArrowStyled component with the styled. div tag. Then string that we pass into the tag has the rotate value set from a prop.

How do you pass parent components to props?

To pass data from a child component to its parent, we can call a parent function from the child component with arguments. The parent function can be passed down to the child as a prop, and the function arguments are the data that the parent will receive.

Can you pass component as prop React?

You can pass a component as props in React by using the built-in children prop. All elements you pass between the opening and closing tags of a component get assigned to the children prop.


1 Answers

Since v0.59.0, you should use React.Component. For example:

/* @flow */

import React from 'react';

const Input = props => <div>Yo</div>

type Props = {
  InputComponent: React.Component<*, *>
};

class App extends React.Component<Props, void> {
  static defaultProps = {
    InputComponent: Input
  };

  render() {
    const { InputComponent } = this.props

    return (
      <div>
        <InputComponent />
      </div>
    )
  }
}

Here is a working example for 0.59.0. As mentioned in the comments, there is a description of the changes here.

:: Before v0.59.0 ::

You should use ReactClass<*> instead of React.Component.

Here is a working example, and the documentation is here!

/**
 * Type of a React class (not to be confused with the type of instances of a
 * React class, which is the React class itself). A React class is any subclass
 * of React$Component. We make the type of a React class parametric over Config,
 * which is derived from some of the type parameters (DefaultProps, Props) of
 * React$Component, abstracting away others (State); whereas a React$Component
 * type is useful for checking the definition of a React class, a ReactClass
 * type (and the corresponding React$Element type, see below) is useful for
 * checking the uses of a React class. The required constraints are set up using
 * a "helper" type alias, that takes an additional type parameter C representing
 * the React class, which is then abstracted with an existential type (*). The *
 * can be thought of as an "auto" instruction to the typechecker, telling it to
 * fill in the type from context.
 */
type ReactClass<Config> = _ReactClass<*, *, Config, *>;
type _ReactClass<DefaultProps, Props, Config: $Diff<Props, DefaultProps>, C: React$Component<DefaultProps, Props, any>> = Class<C>;
like image 177
thejohnbackes Avatar answered Sep 27 '22 18:09

thejohnbackes