From 07a2194d823b7c88fa301e83109af11a95f28f62 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 18 Jun 2024 13:43:21 +0200 Subject: [PATCH 1/4] Add page about React.memo --- data/sidebar_react_latest.json | 1 + pages/docs/react/latest/memo.mdx | 98 ++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 pages/docs/react/latest/memo.mdx diff --git a/data/sidebar_react_latest.json b/data/sidebar_react_latest.json index 21827eb9d..758517284 100644 --- a/data/sidebar_react_latest.json +++ b/data/sidebar_react_latest.json @@ -12,6 +12,7 @@ "events", "refs-and-the-dom", "context", + "memo", "styling", "router", "lazy-components", diff --git a/pages/docs/react/latest/memo.mdx b/pages/docs/react/latest/memo.mdx new file mode 100644 index 000000000..11ccb75f4 --- /dev/null +++ b/pages/docs/react/latest/memo.mdx @@ -0,0 +1,98 @@ +--- +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. + +But React may still re-render it: memoization is a performance optimization, not a guarantee. + + + +```res +@react.component +let make = React.memo((~a: int, ~b: string) => { +
+ {React.int(a)} +
+ {React.string(b)} +
+}) +``` + +```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 + ] + }); + }); +``` + +
+ +## 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, to use the `arePropsEqual` function, you must redefine the `memo` binding. + + + +```res +type propsDef = { + disabled: bool, + onClick: unit => unit, +} + +// Refine memo to satify the compiler. +let memo = React.memoCustomCompareProps(_, (p1, p2) => + p1.disabled == p2.disabled +) + +@react.component(: propsDef) +let make = memo((~disabled, ~onClick) => { + +}) +``` + +```js +import * as React from "react"; +import * as JsxRuntime from "react/jsx-runtime"; + +function memo(__x) { + return React.memo(__x, (function (p1, p2) { + return p1.disabled === p2.disabled; + })); +} + +var make = memo(function (props) { + var onClick = props.onClick; + return JsxRuntime.jsx("button", { + children: "My button", + disabled: props.disabled, + onClick: (function (ev) { + onClick((ev.preventDefault(), undefined)); + }) + }); + }); +``` + + \ No newline at end of file From c11b35719dfbd098729a7ea044a7e685636fa946 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 19 Jun 2024 13:36:39 +0200 Subject: [PATCH 2/4] Simplify arePropsEqual sample --- pages/docs/react/latest/memo.mdx | 48 +++++++++++++------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/pages/docs/react/latest/memo.mdx b/pages/docs/react/latest/memo.mdx index 11ccb75f4..c52b20ec9 100644 --- a/pages/docs/react/latest/memo.mdx +++ b/pages/docs/react/latest/memo.mdx @@ -48,51 +48,43 @@ var make = React.memo(function (props) { 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, to use the `arePropsEqual` function, you must redefine the `memo` binding. +In ReScript, to use the `arePropsEqual` function, you must redefine the `make` binding with `React.memoCustomCompareProps`. ```res -type propsDef = { - disabled: bool, - onClick: unit => unit, -} - -// Refine memo to satify the compiler. -let memo = React.memoCustomCompareProps(_, (p1, p2) => - p1.disabled == p2.disabled -) - -@react.component(: propsDef) -let make = memo((~disabled, ~onClick) => { +@react.component +let make = (~disabled, ~onClick) => { -}) +} + +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 memo(__x) { - return React.memo(__x, (function (p1, p2) { - return p1.disabled === p2.disabled; - })); +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 = memo(function (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; + })); ``` \ No newline at end of file From 987e992c81be9a2a5a9803b2714ceec57e75bb0b Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 19 Jun 2024 14:08:37 +0200 Subject: [PATCH 3/4] Uppercase description start. --- pages/docs/react/latest/memo.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/docs/react/latest/memo.mdx b/pages/docs/react/latest/memo.mdx index c52b20ec9..97e2c7e43 100644 --- a/pages/docs/react/latest/memo.mdx +++ b/pages/docs/react/latest/memo.mdx @@ -1,6 +1,6 @@ --- title: memo -description: "using React.memo" +description: "Using React.memo" canonical: "/docs/react/latest/memo" --- From cd4b530ec801ec521bcfd1dc387958ed44e853bd Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 19 Jun 2024 14:48:26 +0200 Subject: [PATCH 4/4] Show options to use memoCustomCompareProps --- pages/docs/react/latest/memo.mdx | 49 ++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/pages/docs/react/latest/memo.mdx b/pages/docs/react/latest/memo.mdx index 97e2c7e43..34b05a8c4 100644 --- a/pages/docs/react/latest/memo.mdx +++ b/pages/docs/react/latest/memo.mdx @@ -48,9 +48,11 @@ var make = React.memo(function (props) { 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, to use the `arePropsEqual` function, you must redefine the `make` binding with `React.memoCustomCompareProps`. +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: + + ```res @react.component @@ -87,4 +89,45 @@ var make = React.memo(Playground, (function (p1, p2) { })); ``` - \ No newline at end of file + + + +Another approach is to use a custom prop type and remove the `@react.component` annotation. + + + +```res +type props = { + disabled: bool, + onClick: JsxEvent.Mouse.t => unit, +} + +let make = React.memoCustomCompareProps( + ({disabled, onClick}) => { + + }, + (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; + })); +``` + +