Current state of React context

reasonreact

#1

Is anyone using the React context with ReasonReact? The documentation only mentions the legacy context API and looking at the source code, it seems like the bindings are incomplete.


#2

Currently, one option is to use React.createElement to render the provider and React.useContext hook to consume the context:

/* MyContext.re */
let context = React.createContext("Hello World");
let provider = React.Context.provider(context);

/* Example rendering of the provider */
[@react.component]
let make = () => {
  React.createElement(MyContext.provider, { "value": "Hello World", "children": (<App />) });
};

/* Example useContext usage */
[@react.component]
let make = () => {
  let value = React.useContext(MyContext.context);
  <div>{React.string(value)}</div>
};

There may be an opportunity to improve the ergonomics or documentation here.
Perhaps @rickyvetter has some thoughts on this?

EDIT: you can also define a Provider module with make and makeProps yourself to make rendering of the provider a bit nicer:

/* MyContext.re */
let context = React.createContext("Hello World");

module Provider = {
  let makeProps = (~value, ~children, ()) => {"value": value, "children": children}

  let make = React.Context.provider(context);
}

/* Rendering of the provider */
[@react.component]
let make = () => {
  <MyContext.Provider value="Hello World">
    <Comp />
  </MyContext.Provider>;
};

#3

Thank you for your help! I ended up using the second option. I hope there is a plan to provide a nicer way to achieve that.


#4

Hello everyone.

Your second option is great I got it working to use values in components but how would you go about updating the values from the component?

Is it possible in Reason?

Thank you for your help


#5

Updating would look similar to the docs example you linked.
Instead of just the value, you could pass the tuple (value, setValue) as a context value, and use it in consuming component:

/* MyContext.re */
let context = React.createContext(("Hello World", _ => ());

/* Providing context */
[@react.component]
let make = () => {
  let (value, setValue) = React.useState(() => "Hello World");
  <MyContext.Provider value={(value, setValue)}>
    <Comp />
  </MyContext.Provider>;
};

/* Using context */
[@react.component]
let make = () => {
  let (value, setValue) = React.useContext(MyContext.context);
  let onClick = _ => setValue(prevValue => prevValue ++ "!");
  <button onClick>{React.string(value)}</button>
};

#6

Not that I have much to add but you can also pass the value and setValue singularly in separate context providers. Since the setValue function is never going to change you can avoid re-rendering in components that don’t need to consume the value.