While this particular HOC isn't that useful, the point is that it allows you to add functionality to any component without repeating the code (trivial in this case, but...)
Here is a contrived snippet showing two different components utilizing the added counter logic in different ways.
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
function withCountState(Wrapped) {
return function (props) {
const [count, setCount] = React.useState(0);
props['count'] = count;
props['setCount'] = setCount;
return <Wrapped {...props} />;
}
}
const Wrapped = (props) => {
const { count, setCount } = props;
return (
<div>
<h1>Counter Functional Component</h1>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Increment count
</button>
</div>);
};
const WrappedList = (props) => {
const { count, setCount } = props;
const listItems = []
for (let i = 0; i < count; i++) {
listItems.push(<li key={i}> List item: {i}</li>);
}
return (
<div>
<h1>Another Functional Component</h1>
<ul>
{
listItems.map(li => li)
}
</ul>
<button onClick={() => setCount(count + 1)}>
Add Item
</button>
</div>);
};
function App() {
const EnhancedWrapped = withCountState(Wrapped);
const EnhancedWrappedList = withCountState(WrappedList);
return (
<div className="App">
<EnhancedWrapped />
<EnhancedWrappedList />
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
<!-- end snippet -->
That's [*property spread notation*][1]. It was added in ES2018 (spread for arrays/iterables was earlier, ES2015), but it's been supported in React projects for a long time via transpilation (as "[JSX spread attributes][2]" even though you could do it elsewhere, too, not just attributes).
`{...this.props}` *spreads out* the "own" enumerable properties in `props` as discrete properties on the `Modal` element you're creating. For instance, if `this.props` contained `a: 1` and `b: 2`, then
<Modal {...this.props} title='Modal heading' animation={false}>
would be the same as
<Modal a={this.props.a} b={this.props.b} title='Modal heading' animation={false}>
But it's dynamic, so whatever "own" properties are in `props` are included.
Since `children` is an "own" property in `props`, spread will include it. So if the component where this appears had child elements, they'll be passed on to `Modal`. Putting child elements between the opening tag and closing tags is just syntactic sugar — the good kind — for putting a `children` property in the opening tag. Example:
<!-- begin snippet: js hide: true console: true babel: true -->
<!-- language: lang-js -->
class Example extends React.Component {
render() {
const { className, children } = this.props;
return (
<div className={className}>
{children}
</div>
);
}
}
ReactDOM.render(
[
<Example className="first">
<span>Child in first</span>
</Example>,
<Example className="second" children={<span>Child in second</span>} />
],
document.getElementById("root")
);
<!-- language: lang-css -->
.first {
color: green;
}
.second {
color: blue;
}
<!-- language: lang-html -->
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!-- end snippet -->
Spread notation is handy not only for that use case, but for creating a new object with most (or all) of the properties of an existing object — which comes up a lot when you're updating state, since you can't modify state directly:
this.setState(prevState => {
return {foo: {...prevState.foo, a: "updated"}};
});
That replaces `this.state.foo` with a new object with all the same properties as `foo` except the `a` property, which becomes `"updated"`:
<!-- begin snippet: js hide: true console: true babel: false -->
<!-- language: lang-js -->
const obj = {
foo: {
a: 1,
b: 2,
c: 3
}
};
console.log("original", obj.foo);
// Creates a NEW object and assigns it to `obj.foo`
obj.foo = {...obj.foo, a: "updated"};
console.log("updated", obj.foo);
<!-- language: lang-css -->
.as-console-wrapper {
max-height: 100% !important;
}
<!-- end snippet -->
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
[2]: https://reactjs.org/docs/jsx-in-depth.html#spread-attributes