Skip to content

Commit eda1f43

Browse files
committed
Add docs for @react.componentWithProps
1 parent 75ef824 commit eda1f43

File tree

2 files changed

+119
-3
lines changed

2 files changed

+119
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
id: "react-component-with-props-decorator"
3+
keywords: ["react", "component", "props", "decorator"]
4+
name: "@react.componentWithProps"
5+
summary: "This is the `@react.componentWithProps` decorator."
6+
category: "decorators"
7+
---
8+
9+
The `@react.componentWithProps` decorator is used to annotate functions that are [React](/docs/react/latest/elements-and-jsx) components which take in a record type as prop.
10+
This decorator will ensure your component gets an uppercased name.
11+
12+
13+
> **Note**
14+
> The `@react.componentWithProps` decorator requires the [react-jsx or jsx config](/docs/react/latest/installation) to be set in your `rescript.json` to enable the required React transformations.
15+
16+
### Example
17+
18+
<CodeTab labels={["ReScript", "JS Output"]}>
19+
20+
```res
21+
module Hey = {
22+
type props = {
23+
name: string,
24+
}
25+
26+
@react.componentWithProps
27+
let make = (props: props) => {
28+
<button> {React.string("Hello " ++ props.name ++ "!")} </button>
29+
}
30+
}
31+
```
32+
33+
```js
34+
import * as JsxRuntime from "react/jsx-runtime";
35+
36+
function Playground$Hey(props) {
37+
return JsxRuntime.jsx("button", {
38+
children: "Hello " + props.name + "!"
39+
});
40+
}
41+
42+
let Hey = {
43+
make: Playground$Hey
44+
};
45+
```
46+
47+
</CodeTab>
48+
49+
### References
50+
51+
* [React Components](/docs/react/latest/components-and-props)

pages/docs/react/latest/components-and-props.mdx

+68-3
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ let make = () => {
3939
import * as React from "react";
4040

4141
function Greeting(props) {
42-
return React.createElement("div", undefined, "Hello ReScripters!");
42+
return JsxRuntime.jsx("div", {
43+
children: "Hello ReScripters!"
44+
});
4345
}
4446

4547
var make = Greeting;
@@ -51,7 +53,7 @@ var make = Greeting;
5153

5254
We've created a `Greeting.res` file that contains a `make` function that doesn't receive any props (the function doesn't receive any parameters), and returns a `React.element` that represents `<div> Hello ReScripters! </div>` in the rendered DOM.
5355

54-
You can also see in the the JS output that the function we created was directly translated into the pure JS version of a ReactJS component. Note how a `<div>` transforms into a `React.createElement("div",...)` call in JavaScript.
56+
You can also see in the the JS output that the function we created was directly translated into the pure JS version of a ReactJS component. Note how a `<div>` transforms into a `JsxRuntime.jsx("div",...)` call in JavaScript.
5557

5658
## Defining Props
5759

@@ -272,6 +274,69 @@ The best way to approach this kind of issue is by using props instead of childre
272274
**The best use-case for `children` is to pass down `React.element`s without any semantic order or implementation details!**
273275

274276

277+
## @react decorators
278+
279+
You might've wondered what `@react.component` actually does.
280+
It's a decorator that tells the ReScript compiler to treat the function as a React component, transforming it at the syntax level.
281+
282+
In JavaScript, a React component is just a function that takes props (an object) and returns JSX. In ReScript, props are typically represented as a record type.
283+
The `@react.component` decorator automatically generates that record type and wraps the function for you—so you don't have to.
284+
285+
```res
286+
// Counter.res
287+
288+
@react.component
289+
let make = (~title, ~count) => {
290+
<h1> {React.string(title)} {React.int(count)} </h1>
291+
}
292+
293+
// This is equivalent to writing:
294+
295+
type props = {title: string, count: int}
296+
297+
let \"Counter" = ({title, count}: props) => {
298+
<h1> {React.string(title)} {React.int(count)} </h1>
299+
}
300+
```
301+
302+
However, writing it manually like this means you lose the `make` function name, which prevents JSX from working as expected when using the component elsewhere.
303+
304+
Having an uppercased function name also helps distinguish React components from regular functions in [React DevTools](https://react.dev/learn/react-developer-tools).
305+
306+
If you prefer defining your own props record, you can use `@react.componentWithProps`. This gives you full control over the props type while still generating a proper uppercased component.
307+
308+
<CodeTab labels={["ReScript", "JS Output"]}>
309+
310+
```res
311+
// Counter.res
312+
type props = {title: string, count: int}
313+
314+
@react.componentWithProps
315+
let make = (props: props) => {
316+
<h1>
317+
{React.string(props.title)}
318+
{React.int(props.count)}
319+
</h1>
320+
}
321+
```
322+
323+
```js
324+
import * as JsxRuntime from "react/jsx-runtime";
325+
326+
function Counter(props) {
327+
return JsxRuntime.jsxs("h1", {
328+
children: [
329+
props.title,
330+
props.count
331+
]
332+
});
333+
}
334+
335+
let make = Counter;
336+
```
337+
338+
</CodeTab>
339+
275340
## Props & Type Inference
276341

277342
The ReScript type system is really good at inferring the prop types just by looking at its prop usage.
@@ -405,7 +470,7 @@ let content = <Label title="Test"/>
405470

406471
## Component Naming
407472

408-
Because components are actually a pair of functions, they have to belong to a module to be used in JSX. It makes sense to use these modules for identification purposes as well. `@react.component` automatically adds the name for you based on the module you are in.
473+
Because components are actually a pair of functions, they have to belong to a module to be used in JSX. It makes sense to use these modules for identification purposes as well. `@react.component` or `@react.componentWithProps` automatically adds the name for you based on the module you are in.
409474

410475

411476
```res

0 commit comments

Comments
 (0)