Quick Links
  • -Overview
  • -Language Features
  • -JS Interop
  • -Build System
Documentation
Language Manual
Reference for all language features
ReScript & React
First class bindings for ReactJS
GenType
Seamless TypeScript integration
Reanalyze
Dead Code & Termination analysis
Exploration
Packages
Explore third party libraries and bindings
Syntax Lookup
Discover all syntax constructs
APIPlaygroundBlogCommunity
  • Playground
  • Blog
  • Twitter
  • GitHub
  • Forum
rescript-react
Overview
  • Introduction
  • Installation
  • Migrate from JSX v3
Main Concepts
  • Elements & JSX
  • Rendering Elements
  • Components and Props
  • Arrays and Keys
  • Refs and the DOM
  • Context
  • Styling
  • Router
Hooks & State Management
  • Hooks & State Management Overview
  • useEffect Hook
  • useState Hook
  • useReducer Hook
  • useContext Hook
  • useRef Hook
  • Build A Custom Hook
Guides
  • Beyond JSX
    • Component Types
    • JSX Component Interface
    • JSX Under the Hood
  • Forwarding Refs
  • Extensions of props
Docs / rescript-react / Beyond JSX
Edit

Beyond JSX

JSX is a syntax sugar that allows us to use React components in an HTML like manner. A component needs to adhere to certain interface conventions, otherwise it can't be used in JSX. This section will go into detail on how the JSX transformation works and what React APIs are used underneath.

Note: This section requires knowledge about the low level apis for creating elements, such as React.createElement or ReactDOM.createDOMElementVariadic.

Note: This page assumes your bsconfig.json to be set to "jsx": { "version": 4 } to apply the right JSX transformations.

Component Types

A plain React component is defined as a ('props) => React.element function. You can also express a component more efficiently with our shorthand type React.component<'props>.

Here are some examples on how to define your own component types (often useful when interoping with existing JS code, or passing around components):

RES
// Plain function type type friend = {name: string, online: bool} type friendComp = friend => React.element // Equivalent to // ({padding: string, children: React.element}) => React.element type props = {padding: string, children: React.element} type containerComp = React.component<props>

The types above are pretty low level (basically the JS representation of a React component), but since ReScript React has its own ways of defining React components in a more language specific way, let's have a closer look on the anatomy of such a construct.

JSX Component Interface

A ReScript React component needs to be a (sub-)module with a make function and props type to be usable in JSX. To make things easier, we provide a @react.component decorator to create those functions for you:

DecoratedExpanded
module Friend = {
  @react.component
  let make = (~name: string, ~children) => {
    <div>
      {React.string(name)}
      children
    </div>
  }
}

In the expanded output:

  • props: A generated record type that has fields according to the labeled arguments of the make function

  • make: A converted make function that complies to the component interface (props) => React.element

Special Case React.forwardRef

The @react.component decorator also works for React.forwardRef calls:

DecoratedExpanded
module FancyInput = {
  @react.component
  let make = React.forwardRef((~className=?, ~children, ref) =>
    <div>
      // use ref here
    </div>
  )
}

As shown in the expanded output above, our decorator desugars the function passed to React.forwardRef in the same manner as a typical component make function. It also creates a props type with an optional ref field, so we can use it in our JSX call (<FancyInput ref=.../>).

So now that we know how the ReScript React component transformation works, let's have a look on how ReScript transforms our JSX constructs.

JSX Under the Hood

Whenever we are using JSX with a custom component ("capitalized JSX"), we are actually using React.createElement to create a new element. Here is an example of a React component without children:

JSXWithout JSXJS Output
<Friend name="Fred" age=20 />

As you can see, it uses Friend.make to call the React.createElement API. In case you are providing children, it will use React.createElementVariadic instead (which is just a different binding for React.createElement):

JSXWithout JSXJS Output
<Container width=200>
  {React.string("Hello")}
  {React.string("World")}
</Container>

Note that the children: React.null field has no relevance since React will only care about the children array passed as a third argument.

Dom Elements

"Uncapitalized JSX" expressions are treated as DOM elements and will be converted to ReactDOM.createDOMElementVariadic calls:

JSXWithout JSXJS Output
<div title="test"/>

The same goes for uncapitalized JSX with children:

JSXWithout JSXJS Output
<div title="test">
  <span/>
</div>
Build A Custom HookForwarding Refs

© 2024 The ReScript Project

Software and assets distribution powered by KeyCDN.

About
  • Community
  • ReScript Association
Find us on