Skip to content

Commit 8f7072f

Browse files
committed
more module function examples
1 parent f3d7150 commit 8f7072f

File tree

1 file changed

+162
-1
lines changed

1 file changed

+162
-1
lines changed

pages/docs/manual/latest/module-functions.mdx

+162-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ canonical: "/docs/manual/latest/module-functions"
99
Module functions can be used to create modules based on types, values, or functions from other modules.
1010
This is a powerful tool that can be used to created abstractions and reusable code that might not be possible with functions, or might have a runtime cost if done with functions.
1111

12+
## Quick example
1213
Next.js has a `useNavigation` hook that returns an unknown type,
1314
and it's up to the developer to add in a type annotation to define the type of the parameters returned by the hook.
1415
```TS
@@ -96,6 +97,7 @@ export {
9697
```
9798
</ CodeTab>
9899

100+
## Sharing a type with an external binding
99101
This becomes incredibly useful when you need to have types that are unique to a project but shared across multiple components.
100102
Let's say you want to create a library with a `useEnv` hook to load in environment variables found in `import.meta.env`.
101103
```res
@@ -145,4 +147,163 @@ var Env = {
145147

146148
var values = import.meta.env;
147149
```
148-
</ CodeTab>
150+
</ CodeTab>
151+
152+
## Shared functions
153+
You might want to share functions across modules, like a way to log a value or render it in React.
154+
Here's an example of module function that takes in a type and a transform to string function.
155+
156+
```res
157+
module MakeDataModule = (
158+
T: {
159+
type t
160+
let toString: t => string
161+
},
162+
) => {
163+
type t = T.t
164+
let log = a => Console.log("The value is " ++ T.toString(a))
165+
166+
module Render = {
167+
@react.component
168+
let make = (~value) => value->T.toString->React.string
169+
}
170+
}
171+
```
172+
You can now take a module with a type of `t` and a `toString` function and create a new module that has the `log` function and the `Render` component.
173+
<CodeTab labels={["ReScript", "JS Output"]}>
174+
```res
175+
module Person = {
176+
type t = { firstName: string, lastName: string }
177+
let toString = person => person.firstName ++ person.lastName
178+
}
179+
180+
module PersonData = MakeDataModule(Person)
181+
```
182+
183+
```js
184+
// Notice that none of the JS output references the MakeDataModule function
185+
186+
function toString(person) {
187+
return person.firstName + person.lastName;
188+
}
189+
190+
var Person = {
191+
toString: toString
192+
};
193+
194+
function log(a) {
195+
console.log("The value is " + toString(a));
196+
}
197+
198+
function Person$MakeDataModule$Render(props) {
199+
return toString(props.value);
200+
}
201+
202+
var Render = {
203+
make: Person$MakeDataModule$Render
204+
};
205+
206+
var PersonData = {
207+
log: log,
208+
Render: Render
209+
};
210+
```
211+
</CodeTab>
212+
213+
Now the `PersonData` module has the functions from the `MakeDataModule`.
214+
<CodeTab labels={["ReScript", "JS Output"]}>
215+
```res
216+
@react.component
217+
let make = (~person) => {
218+
let handleClick = _ => PersonData.log(person)
219+
<div>
220+
{React.string("Hello ")}
221+
<PersonData.Render value=person />
222+
<button onClick=handleClick>
223+
{React.string("Log value to console")}
224+
</button>
225+
</div>
226+
}
227+
```
228+
```js
229+
function Person$1(props) {
230+
var person = props.person;
231+
var handleClick = function (param) {
232+
log(person);
233+
};
234+
return JsxRuntime.jsxs("div", {
235+
children: [
236+
"Hello ",
237+
JsxRuntime.jsx(Person$MakeDataModule$Render, {
238+
value: person
239+
}),
240+
JsxRuntime.jsx("button", {
241+
children: "Log value to console",
242+
onClick: handleClick
243+
})
244+
]
245+
});
246+
}
247+
```
248+
</CodeTab>
249+
250+
## Dependency injection
251+
Module functions can be used for dependency injection.
252+
Here's an example of injecting in a some config values into a set of functions to access a database.
253+
<CodeTab labels={["ReScript", "JS Output"]}>
254+
```res
255+
module type DbConfig = {
256+
let host: string
257+
let database: string
258+
let username: string
259+
let password: string
260+
}
261+
262+
module MakeDbConnection = (Config: DbConfig) => {
263+
type client = {
264+
write: string => unit,
265+
read: string => string,
266+
}
267+
@module("database.js")
268+
external makeClient: (string, string, string, string) => client = "makeClient"
269+
270+
let client = makeClient(Config.host, Config.database, Config.username, Config.password)
271+
}
272+
273+
module Db = MakeDbConnection({
274+
let host = "localhost"
275+
let database = "mydb"
276+
let username = "root"
277+
let password = "password"
278+
})
279+
280+
let updateDb = Db.client.write("new value")
281+
```
282+
```js
283+
// Generated by ReScript, PLEASE EDIT WITH CARE
284+
285+
import * as DatabaseJs from "database.js";
286+
287+
function MakeDbConnection(Config) {
288+
var client = DatabaseJs.makeClient(Config.host, Config.database, Config.username, Config.password);
289+
return {
290+
client: client
291+
};
292+
}
293+
294+
var client = DatabaseJs.makeClient("localhost", "mydb", "root", "password");
295+
296+
var Db = {
297+
client: client
298+
};
299+
300+
var updateDb = client.write("new value");
301+
302+
export {
303+
MakeDbConnection ,
304+
Db ,
305+
updateDb ,
306+
}
307+
/* client Not a pure module */
308+
```
309+
</CodeTab>

0 commit comments

Comments
 (0)