Skip to content

Instantly share code, notes, and snippets.

@dariooddenino
Last active August 10, 2017 09:30
Show Gist options
  • Save dariooddenino/94345aa2ca86667a4ea47ea8b0aaf022 to your computer and use it in GitHub Desktop.
Save dariooddenino/94345aa2ca86667a4ea47ea8b0aaf022 to your computer and use it in GitHub Desktop.
Trying to create a wrapper function in reason-react.
/**
I'm trying to create a wrapper function that takes a react component and injects Apollo queries as props.
I've got to the point where it works, but:
1) I have to pass all the queries in a single js object with no compiler check if there's corrispondence
between the queries used and the ones the wrapped component is expecting.
2) I can't pass additional props without stuffing all of them inside a single object in the wrapper and then
doing some ugly Js.Obj.assign stuff.
*/
/** This two functions injects all the queries as props in the component */
let createWrapper (query: query) (name: string) :reactWrapper =>
graphqlWithConfig query (graphqlConfig ::name ()) [@bs];
let wrapComponent
(queries: list query)
(component: ReasonReact.reactClass)
:ReasonReact.reactClass =>
List.fold_left (fun c q => (createWrapper q (getQueryName q)) c [@bs]) component queries;
/**
This function is used by the wrapper component to connect the inner component to the queries .
Ideally this function is a standard one, so I ca't manually add types on a per case basis.
*/
let createMake ::name="Wrapper" queries::(queries: list query) ::component ::make => {
let connectedComponent = {
let jsComponent =
ReasonReact.wrapReasonForJs
::component
(fun props => {
/**
In the following example, props here is:
type props = Js.t {.
channelsListQuery: query,
bananasListQuery: query
}
I could have the wrapper components as an argument here, and merge the two objects. But no type checking then.
*/
make ::props [||]
});
let wrapped = wrapComponent queries jsComponent;
ReasonReact.wrapJsForReason reactClass::wrapped props::(Js.Obj.empty ()) [||]
};
let wrapperComponent = ReasonReact.statelessComponent name;
let wrapperMake
(_children: array ReasonReact.reactElement)
:ReasonReact.component ReasonReact.stateless ReasonReact.noRetainedProps => {
...wrapperComponent,
render: fun _self => {
/** Here I would pass the single props object to the connected component */
ReasonReact.element connectedComponent
}
};
wrapperMake
};
/**
Here I could type props manually, but I'd still have no compile check that they correspond to the one actually
passed to the wrapped component
*/
type props = Js.t {.
channelsListQuery: query,
bananasListQuery: query
};
module TestComponent = {
let component = ReasonReact.statelessComponent "TestComponent";
let make props::(props: props) _ => {
...component,
render: fun _self => {
...
}
}
};
module TestWrapper = {
let channelsListQuery =
createQuery {|
query channelsListQuery {
channels {
id
name
}
}
|};
let bananasListQuery =
createQuery {|
query bananasListQuery {
bananas {
id
name
}
}
|};
/**
It could be nice to pass just the whole component module instead of the component and make functions separately,
but it's not that bad.
*/
let make =
createMake
name::"TestWrapper"
queries::[channelsListQuery, bananasListQuery]
component::TestComponent.component
make::TestComponent.make;
};
/**
And then In my App
*/
<TestWrapper /> /** It works! */
/** I could do: */
<TestWrapper additionalProps={ /** big object */ } />
/** What I'd like: */
<TestWrapper foo="bar" baz=2 />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment