Skip to content

Commit f831d59

Browse files
authored
Add React interopt guide (#886)
* Add React interopt guide * Rename to interop * Use CodeTab * Rename interop to import-export-reactjs
1 parent 9e95c50 commit f831d59

File tree

3 files changed

+193
-1
lines changed

3 files changed

+193
-1
lines changed

data/sidebar_react_latest.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"context",
1515
"styling",
1616
"router",
17-
"lazy-components"
17+
"lazy-components",
18+
"import-export-reactjs"
1819
],
1920
"Hooks & State Management": [
2021
"hooks-overview",

pages/docs/manual/latest/import-from-export-to-js.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ canonical: "/docs/manual/latest/import-from-export-to-js"
88

99
You've seen how ReScript's idiomatic [Import & Export](import-export.md) works. This section describes how we work with importing stuff from JavaScript and exporting stuff for JavaScript consumption.
1010

11+
If you're looking for react-specific interop guidance, check out the [React JS Interop guide](../../react/latest/import-export-reactjs.mdx).
12+
1113
**Note**: due to JS ecosystem's module compatibility issues, our advice of keeping your ReScript file's compiled JS output open in a tab applies here **more than ever**, as you don't want to subtly output the wrong JS module import/export code, on top of having to deal with Babel/Webpack/Jest/Node's CommonJS \<-> JavaScript module compatibility shims.
1214

1315
In short: **make sure your bindings below output what you'd have manually written in JS**.
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
---
2+
title: Import / Export ReactJS
3+
description: "Reusing existing React components"
4+
canonical: "/docs/react/latest/import-export-reactjs"
5+
---
6+
7+
# Import / Export ReactJS
8+
9+
Reusing existing React components in ReScript is straightforward.
10+
This guide will walk you through the steps required to import and use React components within ReScript,
11+
including defining component props and handling various import scenarios.
12+
13+
## Basic Example
14+
15+
To reuse a React component in ReScript, create a new module, specify the component's location, and define its props.
16+
17+
<CodeTab labels={["ReScript", "JS Output"]}>
18+
19+
```res
20+
module Confetti = {
21+
@module("react-confetti") @react.component
22+
external make: (~width: int, ~height: int) => React.element = "default"
23+
}
24+
25+
// Assuming we are in App.res
26+
@react.component
27+
let make = () => {
28+
<Confetti width={300} height={300} />
29+
}
30+
```
31+
32+
```js
33+
import ReactConfetti from "react-confetti";
34+
import * as JsxRuntime from "react/jsx-runtime";
35+
36+
var Confetti = {};
37+
38+
function Playground(props) {
39+
return JsxRuntime.jsx(ReactConfetti, {
40+
width: 300,
41+
height: 300
42+
});
43+
}
44+
```
45+
46+
</CodeTab>
47+
48+
## Importing from Relative Paths
49+
50+
You can import components from relative file paths using the `@module` attribute.
51+
Use "default" to indicate the default export, or specify a named export if needed.
52+
53+
### Named Export Example
54+
55+
<CodeTab labels={["ReScript"]}>
56+
57+
```res
58+
// Equivalent of import { Foo } from "bar"
59+
module Foo = {
60+
@module("bar") @react.component
61+
external make: unit => React.element = "Foo"
62+
}
63+
```
64+
65+
</CodeTab>
66+
67+
## Defining Props Types
68+
69+
You can define a separate type for your component's props within the module.
70+
71+
### Props Type Example
72+
73+
<CodeTab labels={["ReScript", "JS Output"]}>
74+
75+
```res
76+
module Confetti = {
77+
type confettiProps = {
78+
width: int,
79+
height: int,
80+
}
81+
82+
@module("react-confetti") @react.component(: confettiProps)
83+
external make: confettiProps => React.element = "default"
84+
}
85+
86+
@react.component
87+
let make = () => {
88+
<Confetti width={300} height={300} />
89+
}
90+
```
91+
92+
```js
93+
import ReactConfetti from "react-confetti";
94+
import * as JsxRuntime from "react/jsx-runtime";
95+
96+
var Confetti = {};
97+
98+
function Playground(props) {
99+
return JsxRuntime.jsx(ReactConfetti, {
100+
width: 300,
101+
height: 300
102+
});
103+
}
104+
```
105+
106+
</CodeTab>
107+
108+
## Optional Props
109+
110+
To define optional props, use the `?` symbol.
111+
112+
<CodeTab labels={["ReScript", "JS Output"]}>
113+
114+
```res
115+
module Confetti = {
116+
type confettiProps = {
117+
width: int,
118+
height: int,
119+
initialVelocityX?: int,
120+
initialVelocityY?: int,
121+
}
122+
123+
@module("react-confetti") @react.component(: confettiProps)
124+
external make: confettiProps => React.element = "default"
125+
}
126+
127+
@react.component
128+
let make = () => {
129+
<Confetti width={300} height={300} />
130+
}
131+
```
132+
133+
```js
134+
import ReactConfetti from "react-confetti";
135+
import * as JsxRuntime from "react/jsx-runtime";
136+
137+
var Confetti = {};
138+
139+
function Playground(props) {
140+
return JsxRuntime.jsx(ReactConfetti, {
141+
width: 300,
142+
height: 300
143+
});
144+
}
145+
```
146+
147+
</CodeTab>
148+
149+
## Extending Built-in DOM Nodes
150+
151+
To accept existing DOM props for a component, extend the `JsxDOM.domProps` type.
152+
153+
<CodeTab labels={["ReScript", "JS Output"]}>
154+
155+
```res
156+
module Foo = {
157+
type fooProps = {
158+
...JsxDOM.domProps,
159+
customProp: string,
160+
}
161+
162+
@module("foo") @react.component(: fooProps)
163+
external make: fooProps => React.element = "default"
164+
}
165+
166+
@react.component
167+
let make = () => {
168+
<Foo width={"300px"} height={"300px"} customProp="bar" />
169+
}
170+
```
171+
172+
```js
173+
import Foo from "foo";
174+
import * as JsxRuntime from "react/jsx-runtime";
175+
176+
var Foo$1 = {};
177+
178+
function Playground(props) {
179+
return JsxRuntime.jsx(Foo, {
180+
height: "300px",
181+
width: "300px",
182+
customProp: "bar"
183+
});
184+
}
185+
```
186+
187+
</CodeTab>
188+
189+
In this example `width` and `height` can be set because `JsxDOM.domProps` was spread into `fooProps`.

0 commit comments

Comments
 (0)