Last active
August 10, 2017 09:30
-
-
Save dariooddenino/94345aa2ca86667a4ea47ea8b0aaf022 to your computer and use it in GitHub Desktop.
Trying to create a wrapper function in reason-react.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
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