Reputation: 3080
I created a sample project to demonstrate a problem I have when trying to use two Higher Order Components (hoc) together.
First in isolation (no errors)
================================
The first hoc withStuff
takes an injected argument and a prop and passes the sum
to the wrapped component.
// withStuff.js
const withStuff = ({argNumber}) => (BaseComponent) => ({propNumber, ...passThroughProps}) => {
const sum = argNumber+propNumber
return <BaseComponent sum={sum} {...passThroughProps} />
}
export default withStuff
The second hoc withExtra
takes an injected function and doubles the result, passing double
to the wrapped component.
// withExtra.js
const withExtra = (extraFunction) => (BaseComponent) => ({...passThroughProps}) => {
const double = 2*extraFunction()
return <BaseComponent double={double} {...passThroughProps} />
}
export default withExtra
This is how a Base
component would use for instance withStuff
(all working fine so far).
// Base.js
import withStuff from './withStuff'
const Base = ({content, sum}) => <div>{content} -sum:{sum}</div>
export default withStuff({argNumber:2})(Base)
=================================
Now comes the problem: trying to use withExtra
inside withStuff
:
import withExtra from './withExtra'
const withStuff = ({argNumber}) => (BaseComponent) => ({propNumber, ...passThroughProps}) => {
const sum = argNumber+propNumber
// this does not work
return withExtra(()=>sum)(<BaseComponent sum={sum} {...passThroughProps}/>)
}
export default withStuff
This returns an error:
Warning: Functions are not valid as a React child.
Is it because now withStuff
is returning a hoc function instead of a component? That function returns a component itself, so I cannot see the problem. How to solve this?
NOTE CODESANDBOX HERE: https://codesandbox.io/s/github/snirp/hoc-test
Upvotes: 1
Views: 402
Reputation: 1032
This should solve it:
return withExtra(() => sum)(BaseComponent)();
https://codesandbox.io/s/hoc-test-thxh0
Upvotes: 1
Reputation: 53934
The problem is that you passing the ReactElement
and not the component.
Refer to what is JSX
behind the scenes.
Note that if you want to add additional properties to given ReactElement
you can use cloneElement
.
const withStuff = ({ argNumber }) => BaseComponent => ({
propNumber,
...passThroughProps
}) => {
const sum = argNumber + propNumber;
const callback = () => sum;
// Like so you passing the node which leads to error
// return withExtra(callback)(<BaseComponent sum={sum} {...passThroughProps}
// Passing the reference
return withExtra(callback)(BaseComponent);
// Passing with additional props
// return withExtra(callback)(React.cloneElement(BaseComponent, ...));
// Equivalent
// const WithExtraProps = withExtra(() => sum)(BaseComponent);
// return <WithExtraProps sum={sum} {...passThroughProps} />;
};
Upvotes: 2
Reputation: 12701
Your passing JSX to withExtra
not a component, Change withStuff
like this :
const withStuff = ({argNumber}) => (BaseComponent) => ({propNumber, ...passThroughProps}) => {
const sum = argNumber+propNumber
// this works
// return <BaseComponent sum={sum} {...passThroughProps} />
const WithExtraComponent = withExtra(()=>sum)(BaseComponent);
return <WithExtraComponent sum={sum} {...passThroughProps}/>
}
https://codesandbox.io/s/hoc-test-pm02u
Upvotes: 1
Reputation: 14395
withExtra
is supposed to get a component, so I think this line
return withExtra(()=>sum)(<BaseComponent sum={sum} {...passThroughProps}/>)
should either be:
return withExtra(()=>sum)(BaseComponent)
or
return withExtra(()=>sum)(() => <BaseComponent sum={sum} {...passThroughProps}/>)
Upvotes: 2