I find this HOC to be more useful than nest alone:
const wrap = (...outerComponents) => wrappedComponent => nest(...outerComponents, wrappedComponent)
const BlueOutline = ({ children }) => <div style={{ border: '3px solid blue' }}>{ children }</div>
const YellowOutline = ({ children }) => <div style={{ border: '3px solid yellow' }}>{ children }</div>
const RedOutline = ({ children }) => <div style={{ border: '3px solid red' }}>{ children }</div>
const withBlueOrRedOutline = branch(
() => process.browser,
wrap(BlueOutline, YellowOutline),
wrap(RedOutline)
)(InnerComponent)
When rendered on the server, the component will be wrapped with a red border. On the client, the component will be wrapped with both a yellow and a blue border.
This is more flexible than nest alone because it can be used to wrap components within a compose pipeline, or in branch, etc.
Are there any plans of including a HOC like this?
How it differs from renderComponent hoc?
@istarkov renderComponent doesn't actually render the children. For example:
const Outer = props => <div>{ props.children }</div>
const Inner = () => <p>foo</p>
renderComponent(Outer)(Inner) // => results in <div></div>
wrap(Outer)(Inner) // => results in <div><p>foo</p></div>
Got you, looks cool, @wuct ?
The idea looks good to me, but I think the name should be wrapBy or wrapWith because it's the base component being wrapped, not outer components. I am not a native speaker so I am not sure which name is better.
@sbking will you provide a PR?
This is very easy to implement
export default const wrapWith = WrapperComponent =>
BaseComponent =>
(children, ...restProps) => (
<WrapperComponent>
<BaseComponent {...restProps }>
{children}
</BaseComponent>
</WrapperComponent>
);
Fiddle:
https://jsfiddle.net/69z2wepo/85362/
It will works unless you also want to offer the possibility to use a component instance as a wrapper
But that's a bit awkward because you have to override children or extract the constructor
Strongly agree with this - I was hoping to use nest to turn providers into HOCs. I'd like to do something like this:
export default compose(
injectJss("insertion-point-jss"),
wrap(
({children}) => <MuiThemeProvider theme={styles.theme}>{children}</MuiThemeProvider>,
({children}) => <Provider store={store} >{children}</Provider>,
({children}) => <ConnectedRouter history={history} >{children}</ConnectedRouter>,
)
)(App);
which seems like something recompose was made for. Unless thats actually a terrible antipattern, hahaha. I'll use the existing 'wrap' function as written in my own code, but I'd like it if it was part of the recompose library
@mattishii I'm not sure what does your wrap do. It seems like it is different from the original proposal.
Nope it does the exact same thing, I used sbking's code. I actually don't see much use for nest if it can't be used as an hoc though.
@mattishii Oh, I see. A PR is still welcome :)
I had a similar idea/reaction when trying to think of ways to simplify/clean up the "nested providers around <App />" in some application code. I saw recompose's nest mentioned in a blog post, but I felt that surely the more idiomatic approach (at least for a library as recompose) would be to provide a function to transform a "provider component" into a HOC.
This is a different function than the wrap defined above, but I think it is similar in spirit, also trying to solve the same problem. What I came up with is something like this (untested, also lacking displayName etc):
const asHOC = (ProviderComp, providerProps) => Comp => props =>
<ProviderComp {...providerProps}><Comp {...props} /></ProviderComp>;
which would (hopefully, unless I messed up) allow for the following for @mattishii's example above:
export default compose(
injectJss("insertion-point-jss"),
asHOC(MuiThemeProvider, { theme: styles.theme }),
asHOC(Provider, { store }),
asHOC(ConnectedRouter, { history }),
)(App);
I intentionally only map one component to one HOC, and rely on function composition to compose them, since I feel that's cleaner/more flexible. Also not a fan of having to specify functional components and explicitly render children, which is why I opted for "provide component + object of props" as the HOC's parameters instead.
Not saying this is better--just a different way to approach the same underlying problem. Discussion welcome! 馃槂
export const wrapWith = WrapperComponent =>
BaseComponent =>
props => (
<WrapperComponent {...props }>
<BaseComponent {...props }/>
</WrapperComponent>
I'm going to close this ticket since it's stale. Please feel free to reopen it if you have any further thought.
Most helpful comment
@mattishii Oh, I see. A PR is still welcome :)