Something simple is tripping up my logic here:
I have a HOC AnimateOnLoad
which renders a default content (used within react-router
) within the page component.
const DefaultLayout = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={matchProps => (
<div className="page-container">
{AnimateOnLoad(
<div className="container">
<Head />
<Nav />
<Component {...matchProps} />
</div>
)}
<Footer />
</div>
)}
/>
);
The animateONLoad
HOC looks like this:
const AnimateOnLoad = WrappedComponent =>
class Animator extends Component {
constructor(props) {
super(props);
this.ele = React.createRef();
}
componentDidMount() {
Kute.fromTo(
this.ele.current,
{ opacity: 0.3 },
{ opacity: 1, duration: 120 }
).start();
}
render() {
return (
<div className="animator" ref={this.ele}>
<WrappedComponent {...this.props} />
</div>
);
}
};
However, I am getting an error:
Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
which doesn't make sense to me as I am returning a Component
from AnimateOnLoad()
;
Thank you.
Root cause of your error is this
This may happen if you return a Component instead of <Component />
@ShubhamKhatri Answer will resolve your issue. I want to expand his answer.
Don’t Use HOCs Inside the render Method
React’s diffing algorithm (called reconciliation) uses component identity to determine whether it should update the existing subtree or throw it away and mount a new one. If the component returned from render is identical (===) to the component from the previous render, React recursively updates the subtree by diffing it with the new one. If they’re not equal, the previous subtree is unmounted completely.
render() {
// A new version of Animate is created on every render
// Animate1 !== Animate2
const Animate = AnimateOnLoad(MyComponent);
// That causes the entire subtree to unmount/remount each time!
return <Animate />;
}
Notice how HOC is used outside render in his answer.
The problem here isn’t just about performance — remounting a component causes the state of that component and all of its children to be lost.
That's why its very important to apply HOCs outside the component definition so that the resulting component is created only once. Then, its identity will be consistent across renders. This is usually what you want, anyway.
Reference: https://reactjs.org/docs/higher-order-components.html#dont-use-hocs-inside-the-render-method
You aren't using the AnimateOnLoad
HOC correctly. You need to use it like
const CustomComp = (matchProps) => (
<div className="container">
<Head />
<Nav />
<Component {...matchProps} />
</div>
);
const HOCComponent = AnimateOnLoad(CustomComp)
const DefaultLayout = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={matchProps => (
<div className="page-container">
<HOCComponent {...matchProps}/>
<Footer />
</div>
)}
/>
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With