title | description | canonical |
---|---|---|
Context |
Details about Context in ReScript and React |
/docs/react/latest/context |
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
In a typical React application, data is passed top-down (parent to child) via props, but this can be cumbersome for certain types of props (e.g. locale preference, UI theme) that are required by many components within an application. Context provides a way to share values like these between components without having to explicitly pass a prop through every level of the tree.
Note: In ReScript, passing down props is way simpler than in TS / JS due to its JSX prop punning feature and strong type inference, so it's often preferrable to keep it simple and just do props passing. Less magic means more transparency!
Context is designed to share data that can be considered “global” for a tree of React components, such as the current authenticated user, theme, or preferred language. For example, in the code below we manually thread through a “theme” prop in order to style the Button component:
<CodeTab labels={["ReScript", "JS Output"]}>
// src/App.res
type theme = Light | Dark
module Button = {
@react.component
let make = (~theme) => {
let className = switch theme {
| Light => "theme-light"
| Dark => "theme-black"
}
<button className> {React.string("Click me")} </button>
}
}
module ThemedButton = {
@react.component
let make = (~theme) => {
<Button theme />
}
}
module Toolbar = {
@react.component
let make = (~theme) => {
<div>
<ThemedButton theme/>
</div>
}
}
@react.component
let make = () => {
// We define the theme in the
// toplevel App component and
// pass it down
<Toolbar theme=Dark/>
}
function Button(props) {
var className = props.theme ? "theme-black" : "theme-light";
return React.createElement("button", {
className: className
}, "Click me");
}
function ThemedButton(props) {
return React.createElement(App$Button, {
theme: props.theme
});
}
function Toolbar(props) {
return React.createElement("div", undefined, React.createElement(App$ThemedButton, {
theme: props.theme
}));
}
function App(props) {
return React.createElement(App$Toolbar, {
theme: /* Dark */1
});
}
Using context, we can avoid passing props through intermediate elements:
<CodeTab labels={["ReScript", "JS Output"]}>
// src/App.res
module ThemeContext = {
type theme = Light | Dark
let context = React.createContext(Light)
module Provider = {
let make = React.Context.provider(context)
}
}
module Button = {
@react.component
let make = (~theme) => {
let className = switch theme {
| ThemeContext.Light => "theme-light"
| Dark => "theme-black"
}
<button className> {React.string("Click me")} </button>
}
}
module ThemedButton = {
@react.component
let make = () => {
let theme = React.useContext(ThemeContext.context)
<Button theme />
}
}
module Toolbar = {
@react.component
let make = () => {
<div>
<ThemedButton />
</div>
}
}
@react.component
let make = () => {
<ThemeContext.Provider value=ThemeContext.Dark>
<div>
<Toolbar />
</div>
</ThemeContext.Provider>
}
var context = React.createContext(/* Light */0);
var make = context.Provider;
var Provider = {
make: make
};
var ThemeContext = {
context: context,
Provider: Provider
};
function App$Button(props) {
var className = props.theme ? "theme-black" : "theme-light";
return React.createElement("button", {
className: className
}, "Click me");
}
var Button = {
make: App$Button
};
function App$ThemedButton(props) {
var theme = React.useContext(context);
return React.createElement(App$Button, {
theme: theme
});
}
var ThemedButton = {
make: App$ThemedButton
};
function App$Toolbar(props) {
return React.createElement("div", undefined, React.createElement(App$ThemedButton, {}));
}
var Toolbar = {
make: App$Toolbar
};
function App(props) {
return React.createElement(make, {
value: /* Dark */1,
children: React.createElement("div", undefined, React.createElement(App$Toolbar, {}))
});
}