diff --git a/data/sidebar_react_latest.json b/data/sidebar_react_latest.json index a2a47d615..d2d9d3a79 100644 --- a/data/sidebar_react_latest.json +++ b/data/sidebar_react_latest.json @@ -16,7 +16,8 @@ "styling", "router", "lazy-components", - "import-export-reactjs" + "import-export-reactjs", + "server-components" ], "Hooks & State Management": [ "hooks-overview", diff --git a/pages/docs/react/latest/server-components.mdx b/pages/docs/react/latest/server-components.mdx new file mode 100644 index 000000000..93621ab99 --- /dev/null +++ b/pages/docs/react/latest/server-components.mdx @@ -0,0 +1,228 @@ +--- +title: Server Components +description: "Creating React components" +canonical: "/docs/react/latest/server-components" +--- + +# Server Components + +ReScript allows you to create server components as described in [React 19](https://react.dev/reference/rsc/server-components). + +## Server Functions + +To mark a file exposing functions as [Server Functions](https://react.dev/reference/rsc/server-functions), +you can use the `@@directive("'use server'")` tag. + + + +```res example +// src/actions/MyActions.res +@@directive("'use server'") + +let myHelper = () => "Hello from the server!" + +let helloWorld = async () => { + let response = myHelper() + response +} +``` +```js +'use server' +// Generated by ReScript, PLEASE EDIT WITH CARE + + +function myHelper() { + return "Hello from the server!"; +} + +async function helloWorld() { + return "Hello from the server!"; +} + +export { + myHelper, + helloWorld, +} +``` + + + +**Warning:** It is recommended to use an interface file here, to ensure only the functions you want to expose are exposed. + +```res +// src/actions/MyActions.resi +let helloWorld: unit => Promise +``` + +`myHelper` will remain unexported with this change. + +## Server Components + +[Server components](https://react.dev/reference/rsc/server-components) can be async. + + + +```res example +// src/pages/Index.res +let data = [1, 2, 3] +let getData = () => Promise.resolve(data) + +@react.component +let make = async () => { + // fetch some data from somewhere + let data = await getData() + + +

{React.string("Hello from server component")}

+ + + +} + +// Export as default +let default = make +``` +```js +'use server' +import * as JsxRuntime from "react/jsx-runtime"; + +async function make(param) { + await getData(); + return JsxRuntime.jsx("html", { + children: JsxRuntime.jsx("body", { + children: JsxRuntime.jsx("h1", { + children: "Hello from server component" + }) + }) + }); +} + +let Index = make; + +let make$1 = Index; + +let $$default = Index; + +export { + make$1 as make, + $$default as default, +} +``` + +
+ +A server function can be inlined in a server component and passed as prop to a client component. + + + +```res +module ClientComp = { + @react.component @module("some-module") + external make: (~submit: int => promise) => React.element = + "SomeClientComp" +} + +let data = [1, 2, 3] +let getData = () => Promise.resolve(data) + +@react.component +let make = async () => { + let data = await getData() + + let addData = + @directive("'use server'") + async (id: int) => { + // add to data store + data->Array.push(id) + true + } + + +

{React.string("Hello from server component")}

+
    + {data->Array.map(id =>
  • {React.int(id)}
  • )->React.array} +
+ + + +} +``` +```js +import * as SomeModule from "some-module"; + +let data = [ + 1, + 2, + 3 +]; + +function getData() { + return Promise.resolve(data); +} + +async function make(param) { + let data$1 = await Promise.resolve(data); + let addData = async id => { + 'use server'; + data$1.push(id); + return true; + }; + return JsxRuntime.jsx("html", { + children: JsxRuntime.jsxs("body", { + children: [ + JsxRuntime.jsx("h1", { + children: "Hello from server component" + }), + JsxRuntime.jsx("ul", { + children: data$1.map(id => JsxRuntime.jsx("li", { + children: id + })) + }), + JsxRuntime.jsx(SomeModule.SomeClientComp, { + submit: addData + }) + ] + }) + }); +} +``` + +
+ +**Note** that when decorating the function with `@directive("'use server'")`, we use a single `@`, where to annotate an entire file we use `@@directive("'use server'")`. + +## Client Components + +[Client components](https://react.dev/reference/rsc/use-client) should use the `@@directive("'use client'")` attribute. + + + +```res +// src/components/ClientComp.res +@@directive("'use client'") + +@react.component +let make = (~submit) => +``` +```js +use client' +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as JsxRuntime from "react/jsx-runtime"; + +function ClientComp(props) { + return JsxRuntime.jsx("button", { + children: "yow from client" + }); +} + +let make = ClientComp; + +export { + make, +} +``` + +