diff --git a/data/sidebar_react_latest.json b/data/sidebar_react_latest.json index 3a2d32fda..21827eb9d 100644 --- a/data/sidebar_react_latest.json +++ b/data/sidebar_react_latest.json @@ -14,7 +14,8 @@ "context", "styling", "router", - "lazy-components" + "lazy-components", + "import-export-reactjs" ], "Hooks & State Management": [ "hooks-overview", diff --git a/pages/docs/manual/latest/import-from-export-to-js.mdx b/pages/docs/manual/latest/import-from-export-to-js.mdx index 4922ec456..6328666c1 100644 --- a/pages/docs/manual/latest/import-from-export-to-js.mdx +++ b/pages/docs/manual/latest/import-from-export-to-js.mdx @@ -8,6 +8,8 @@ canonical: "/docs/manual/latest/import-from-export-to-js" 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. +If you're looking for react-specific interop guidance, check out the [React JS Interop guide](../../react/latest/import-export-reactjs.mdx). + **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. In short: **make sure your bindings below output what you'd have manually written in JS**. diff --git a/pages/docs/react/latest/import-export-reactjs.mdx b/pages/docs/react/latest/import-export-reactjs.mdx new file mode 100644 index 000000000..dc4717af7 --- /dev/null +++ b/pages/docs/react/latest/import-export-reactjs.mdx @@ -0,0 +1,189 @@ +--- +title: Import / Export ReactJS +description: "Reusing existing React components" +canonical: "/docs/react/latest/import-export-reactjs" +--- + +# Import / Export ReactJS + +Reusing existing React components in ReScript is straightforward. +This guide will walk you through the steps required to import and use React components within ReScript, +including defining component props and handling various import scenarios. + +## Basic Example + +To reuse a React component in ReScript, create a new module, specify the component's location, and define its props. + + + +```res +module Confetti = { + @module("react-confetti") @react.component + external make: (~width: int, ~height: int) => React.element = "default" +} + +// Assuming we are in App.res +@react.component +let make = () => { + +} +``` + +```js +import ReactConfetti from "react-confetti"; +import * as JsxRuntime from "react/jsx-runtime"; + +var Confetti = {}; + +function Playground(props) { + return JsxRuntime.jsx(ReactConfetti, { + width: 300, + height: 300 + }); +} +``` + + + +## Importing from Relative Paths + +You can import components from relative file paths using the `@module` attribute. +Use "default" to indicate the default export, or specify a named export if needed. + +### Named Export Example + + + +```res +// Equivalent of import { Foo } from "bar" +module Foo = { + @module("bar") @react.component + external make: unit => React.element = "Foo" +} +``` + + + +## Defining Props Types + +You can define a separate type for your component's props within the module. + +### Props Type Example + + + +```res +module Confetti = { + type confettiProps = { + width: int, + height: int, + } + + @module("react-confetti") @react.component(: confettiProps) + external make: confettiProps => React.element = "default" +} + +@react.component +let make = () => { + +} +``` + +```js +import ReactConfetti from "react-confetti"; +import * as JsxRuntime from "react/jsx-runtime"; + +var Confetti = {}; + +function Playground(props) { + return JsxRuntime.jsx(ReactConfetti, { + width: 300, + height: 300 + }); +} +``` + + + +## Optional Props + +To define optional props, use the `?` symbol. + + + +```res +module Confetti = { + type confettiProps = { + width: int, + height: int, + initialVelocityX?: int, + initialVelocityY?: int, + } + + @module("react-confetti") @react.component(: confettiProps) + external make: confettiProps => React.element = "default" +} + +@react.component +let make = () => { + +} +``` + +```js +import ReactConfetti from "react-confetti"; +import * as JsxRuntime from "react/jsx-runtime"; + +var Confetti = {}; + +function Playground(props) { + return JsxRuntime.jsx(ReactConfetti, { + width: 300, + height: 300 + }); +} +``` + + + +## Extending Built-in DOM Nodes + +To accept existing DOM props for a component, extend the `JsxDOM.domProps` type. + + + +```res +module Foo = { + type fooProps = { + ...JsxDOM.domProps, + customProp: string, + } + + @module("foo") @react.component(: fooProps) + external make: fooProps => React.element = "default" +} + +@react.component +let make = () => { + +} +``` + +```js +import Foo from "foo"; +import * as JsxRuntime from "react/jsx-runtime"; + +var Foo$1 = {}; + +function Playground(props) { + return JsxRuntime.jsx(Foo, { + height: "300px", + width: "300px", + customProp: "bar" + }); +} +``` + + + +In this example `width` and `height` can be set because `JsxDOM.domProps` was spread into `fooProps`.