reason-react
reason-react copied to clipboard
Cannot use memoCustomCompareProps
Attempting to use React.memoCustomCompareProps throws the following compiler error:
Invalid_argument("react.component calls can only be on function definitions or component wrappers (forwardRef, memo).")
The same is true of React.Context.provider(context)
Can you give an example of how context was giving you trouble? It can work fine if you drop out of JSX with something like
let context = React.createContext(defaultContextValue);
React.Context.provider(context);
[@react.component]
let make = (~val, ~children) => {
React.createElement(
provider,
{"value": ~val, "children": children},
);
};
Or if you copy over the make + makeProps directly from provider.
Looking at memoCustomCompareProps!
@rickyvetter do you know if the current context API is final? It is a bit cumbersome and not obvious right now. Since it is not documented yet and was not mentioned in the release notes I guess it is still a work in process.
These two options work right now:
module Provider = {
let provider = React.Context.provider(context);
[@react.component]
let make = (~value, ~children) => {
React.createElement(provider, {"value": value, "children": children});
};
};
and
module Provider = {
let makeProps = (~value, ~children, ()) => {
"value": value,
"children": children,
};
let make = React.Context.provider(context);
};
but thats kind of "manual", I was expecting something similar to:
module Provider =
React.Context.Provider.Make({
type t = int;
let context = React.createContext(0);
});
implemented like:
module type S = {
type t;
let context: React.Context.t(t);
};
module Make = (C: S) => {
let makeProps = (~value, ~children, ()) => {
"value": value,
"children": children,
};
let make = React.Context.provider(context);
};
or maybe for the whole context bundle to be created with a functor (resulting in a module with Consumer/Provider submodules)
Functor bundling everything:
module type CONFIG = {
type t;
let initialValue: t;
};
module Make = (Config: CONFIG) => {
type t = Config.t;
let context = React.createContext(Config.initialValue);
let use = () => React.useContext(context);
module Provider = {
[@react.component]
let make = {
let provider = React.Context.provider(context);
(~value=Config.initialValue, ~children) => {
React.createElement(
provider,
{"value": value, "children": children},
);
};
};
};
module Consumer = {
[@react.component]
let make = (~children) => <> {children(use())} </>;
};
};
Example
module MyContext =
Context.Make({
type t = string;
let initialValue = "hello";
});
then
<MyContext.Provider value="Bye">
<MyContext.Consumer>
{value => s(value)}
</MyContext.Consumer>
</MyContext.Provider>
and also
let myContext = MyContext.use();
// or
let myContext = React.useContext(MyContext.context);
I've found a workaround for this, which is so simple that it suggests changing this in reason-react itself might be a single line change somewhere (will see if I can PR this separately):
let memo = React.memoCustomCompareProps(_, (_, _) => true);
[@react.component]
let make = memo(() => <View />);
EDIT: I've had a look at the ppx code and I'm afraid it's beyond me!
Would be good to find a fix for this!