Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What's the replacement for ReactNode, ReactType, and ReactInstance? #151

Open
cmeeren opened this issue Apr 17, 2019 · 8 comments
Open

What's the replacement for ReactNode, ReactType, and ReactInstance? #151

cmeeren opened this issue Apr 17, 2019 · 8 comments

Comments

@cmeeren
Copy link
Contributor

cmeeren commented Apr 17, 2019

I'm currently making a PR to update Fable.MaterialUI to Fable.Core 3 and Fable.React 5. The API makes use of ReactNode, ReactType, and ReactInstance, none of which are available any longer.

Should ReactElement be used instead for all of these?

If you need more context to answer this question, here are examples in the (original) MaterialUI documentation where the three types are used in the current bindings:

@alfonsogarciacaro
Copy link
Member

alfonsogarciacaro commented Apr 17, 2019

In Fable.React 5 we've tried too simplify the interfaces as they were translated from the React Typescript definitions because they were quite complicated. Looking at the samples you kindly provided the equivalences seem to be:

  • ReactNode -> ReactElement
  • ReactType -> ReactElementType (use the helpers in ReactElementType module to instantiate it from a type, a function, etc)
  • ReactInstance -> This is a bit tricky, it seems to accept both ReactElement and ReactElementType. In that case you could use Fable's U2<,> or add an extra union case with CompiledName to allow for "overloads" as in here.
type MenuProps =
   | AnchorEl of ReactElement
   | [<CompiledName("anchorEl")>] AnchorElType of ReactElementType

@cmeeren
Copy link
Contributor Author

cmeeren commented Apr 17, 2019

Thanks for the quick reply!

What is actually ReactElement and ReactElementType? In this context, what is the usage difference between them in F# for such a props API? What is possible with one that the other does not allow for?

Also, ReactElementType is generic, but I have no idea what props type to supply because none of the three previous types are generic. Do you have any idea? Does it make sense to supply obj?

@alfonsogarciacaro
Copy link
Member

ReactElement are instances of React elements, that is, nodes in the Virtual DOM. ReactElementType are constructors for such elements (basically the components, although the word "component" is usually associated with classes). You can build an element using ReactElementType.create, but most of the times you will use other helpers.

Again, this is a simplification and you may find different wording/concepts when checking React documentation or tutorials.

It's true that the generic makes it difficult to create a prop accepting any kind of ReactElementType, so I just added a non generic version in Fable.React 5.1.0. Now you can do:

// In fable-material-ui
    type MaterialProp =
        | Component of ReactElementType
       ..

// Usage

let view (props: {| title: string |}) =
    h1 [] [str props.title]

let menuProps =
    [ Component (ReactElementType.ofFunction view) ]

@cmeeren
Copy link
Contributor Author

cmeeren commented Apr 18, 2019

Thanks! Great to have the non-generic one.

Given a component from a 3rd party library, how would I get a ReactElementType of that?

@MangelMaxime
Copy link
Member

@cmeeren You could just use something like:

let inline bigCalendar (props : BigCalendarProps list) : ReactElement = 
    ofImport "default" "react-big-calendar" (JsInterop.keyValueList CaseRules.LowerFirst props) []

This is what I use in all my bindings and it works. I am not sure why you would need to call ReactElementType interface yourself. This interface is a really low level thing and most of the timùe you should be able to not use it I think.

@cmeeren
Copy link
Contributor Author

cmeeren commented Apr 18, 2019

@MangelMaxime For an example, check the MUI Input API, specifically the inputComponent prop. An example usage is given in Text Fields -> Formatted Inputs. Expand the code for that section and search for inputComponent. You can see that it isn't passed an instance (which AFAIK would be ReactElement), but rather the component itself (dunno if that was the correct term). The most important code is below:

function TextMaskCustom(props) {
  ...  // component implementation
}

...

class FormattedInputs extends React.Component {
  ...
  render() {
    ...
    return (
      ...
          <Input
            ...
            inputComponent={TextMaskCustom}
          />
        ...
  }
}

TextMaskCustom is a functional component, but I would guess (I might be wrong) that inputComponent works the same way with class components too.

Are you saying I still don't need ReactElementType for the inputComponent prop?

@MangelMaxime
Copy link
Member

@cmeeren Ah this is the first time I this kind of code. Then I don't know sorry 😅

React is really cool but sometimes it's really too permissive. I mean there are so many ways and hacks possible to write a component. ^^

@alfonsogarciacaro
Copy link
Member

alfonsogarciacaro commented Apr 18, 2019

Just import it as ReactElementType (with props typed or not depending on your needs):

// Check the documentation of the component to know if you should import the default or a named member
// See https://fable.io/docs/interacting.html#importing-javascript-code

let BigCalendar: ReactElementType<BigCalendarProps> = importDefault "react-big-calendar"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants