jhegedus jhegedus - 1 month ago 9
React JSX Question

ReactComponent vs ReactComponentElement in scalajs-react

I am trying to write some extra scalajs-react documentation but I am confused.

It says here :


A
ReactElement
is a
ReactDOMElement
or a React component.


But it says here:


type ReactElement = ReactComponentElement | ReactDOMElement;



Which one is true ?

How can one explain this contradiction ?

How can
ReactComponent
and
ReactComponentElement
be the same ?

I am confused. Can someone please unconfuse me ?

Answer

Perhaps I'm over simplifying, but the source code indicates that a ReactElement is a javascript object with the properties of a ReactNode and key and ref properties. I wouldn't put as much stock in the vdim / scaladoc comments, they exist to provide a hint to the user, not the compiler. It's trying to say "ReactElement is the common base trait to ReactComponentElement and ReactDomElement", which you can see is indeed true.

   /** ReactElement = ReactComponentElement | ReactDOMElement  */
@js.native
trait ReactElement extends Object with ReactNode {
  def key: UndefOr[String] = js.native
  def ref: UndefOr[String] = js.native
}

/** A React virtual DOM element, such as 'div', 'table', etc. */
@js.native
trait ReactDOMElement extends ReactElement {
  def `type`: String = js.native
  def props : Object = js.native
}

/** An instance of a React component. Prefer using the subtype ReactComponentU instead. */
@js.native
trait ReactComponentElement[Props]
  extends ReactElement
     with HasProps[Props]

The key thing here is that React is a a fairly dynamic javascript framework, so in order to add type safety around in scala.js there end up being a number of "similar but not identical" subtypes create to handle the various underlying states. For instance, ReactComponentU and friends and ReactComponent/ReactComponentElement.

I think in order to document it (more?) successfully than it already has been, you probably will have to document React itself, and then paper over it with the type system -- trying to explain things strictly in terms of the scala.js interface is likely to be quite confusing.