Skip to content

Add page about React.memo #889

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

Merged
merged 4 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data/sidebar_react_latest.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"events",
"refs-and-the-dom",
"context",
"memo",
"styling",
"router",
"lazy-components",
Expand Down
133 changes: 133 additions & 0 deletions pages/docs/react/latest/memo.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
---
title: memo
description: "Using React.memo"
canonical: "/docs/react/latest/memo"
---

# memo

`React.memo` lets you skip re-rendering a component when its props are unchanged.

Wrap a component in memo to get a memoized version of that component.
This memoized version of your component will usually not be re-rendered when its parent component is re-rendered as long as its props have not changed.

<small>But React may still re-render it: memoization is a performance optimization, not a guarantee.</small>

<CodeTab labels={["ReScript", "JS Output"]}>

```res
@react.component
let make = React.memo((~a: int, ~b: string) => {
<div>
{React.int(a)}
<br />
{React.string(b)}
</div>
})
```

```js
import * as React from "react";
import * as JsxRuntime from "react/jsx-runtime";

var make = React.memo(function (props) {
return JsxRuntime.jsxs("div", {
children: [
props.a,
JsxRuntime.jsx("br", {}),
props.b
]
});
});
```

</CodeTab>

## arePropsEqual

In React, memo can accept an optional argument called "arePropsEqual". This function takes two arguments: the previous props and the new props of the component.
It should return true if the old and new props are the same, meaning the component will produce the same output and behavior with the new props as it did with the old ones.

In ReScript, you can use the `arePropsEqual` function with the `React.memoCustomCompareProps` binding. However, `React.memoCustomCompareProps` cannot be combined with `@react.component`.

To work around this, you can redefine the make binding:

<CodeTab labels={["ReScript", "JS Output"]}>

```res
@react.component
let make = (~disabled, ~onClick) => {
<button
disabled={disabled}
onClick={ev => ev->JsxEvent.Mouse.preventDefault->onClick}>
{React.string("My button")}
</button>
}

let make = React.memoCustomCompareProps(make, (p1, p2) =>
p1.disabled == p2.disabled
)
```

```js
import * as React from "react";
import * as JsxRuntime from "react/jsx-runtime";

function Playground(props) {
var onClick = props.onClick;
return JsxRuntime.jsx("button", {
children: "My button",
disabled: props.disabled,
onClick: (function (ev) {
onClick((ev.preventDefault(), undefined));
})
});
}

var make = React.memo(Playground, (function (p1, p2) {
return p1.disabled === p2.disabled;
}));
```

</CodeTab>


Another approach is to use a custom prop type and remove the `@react.component` annotation.

<CodeTab labels={["ReScript", "JS Output"]}>

```res
type props = {
disabled: bool,
onClick: JsxEvent.Mouse.t => unit,
}

let make = React.memoCustomCompareProps(
({disabled, onClick}) => {
<button disabled={disabled} onClick={ev => ev->onClick}>
{React.string("My button")}
</button>
},
(p1, p2) => p1.disabled == p2.disabled,
)
```

```js
import * as React from "react";
import * as JsxRuntime from "react/jsx-runtime";

var make = React.memo((function (param) {
var onClick = param.onClick;
return JsxRuntime.jsx("button", {
children: "My button",
disabled: param.disabled,
onClick: (function (ev) {
onClick(ev);
})
});
}), (function (p1, p2) {
return p1.disabled === p2.disabled;
}));
```

</CodeTab>