I have a common List in mind which looks something like this:
it has one remove button
one input in which user can enter the name of element and on clicking insert the element will be added in the list.
For this i have added HOC like this:
function ListHOC(Component, data, listName, placeholder) {
return class extends React.Component {
constructor() {
super();
this.state = { data, element: "" };
}
add = item => {
const { data } = this.state;
data.push(item);
this.setState({ data });
};
remove = keyToRemove => {
const { data } = this.state;
const newData = data.filter(({ key }) => keyToRemove !== key);
this.setState({ data: newData });
};
render() {
const { data, element } = this.state;
const updatedList = data.map(({ name, key }) => (
<div style={{ display: "flex" }} key={key}>
<div>{name}</div>
<button onClick={() => this.remove(key)}>remove</button>
</div>
));
return (
<>
<div>{listName}: </div>
<Component data={updatedList} {...this.props} />
<input
placeholder={placeholder}
onChange={e => this.setState({ element: e.target.value })}
/>
<button
onClick={() => this.add({ name: element, key: data.length + 1 })}
>
insert
</button>
</>
);
}
};
}
one thing i am not sure about is weather to use the input
and button
and listname inside HOC or not
link to codepen: https://codepen.io/saxenanihal95/pen/NWKVJOx?editors=1010
1 Answer 1
There's no reason to use a HOC for this, it can be done more simply and clearly with a component:
class List extends React.Component {
state = { data: this.props.initialData, element: "" };
add = item => {
this.setState(prev => ({ data: prev.data.concat(item) }));
};
remove = keyToRemove => {
this.setState(prev => ({
data: prev.data.filter(({ key }) => keyToRemove !== key)
}));
};
render() {
const { data, element } = this.state;
const { placeholder, listName } = this.props;
return (
<>
<div>{listName}: </div>
{data.map(({ name, key }) => (
<div style={{ display: "flex" }} key={key}>
<div>{name}</div>
<button onClick={() => this.remove(key)}>remove</button>
</div>
))}
<input
placeholder={placeholder}
onChange={e => this.setState({ element: e.target.value })}
/>
<button
onClick={() => this.add({ name: element, key: data.length + 1 })}
>
insert
</button>
</>
);
}
}
const Users = () => (
<List
initialData={[
{ name: "a", key: 1 },
{ name: "b", key: 2 }
]}
listName="Users"
placeholder="insert user"
/>
);
const Comments = () => (
<List initialData={[]} listName="Comments" placeholder="insert comment" />
);
const AnotherList = () => <Users />;
function App() {
return (
<div>
<Users />
<Comments />
<AnotherList />
</div>
);
}
ReactDOM.render(<App />, document.getElementById("app"));
HOCs are generally better for cross-cutting concerns, or behavior (not presentation) which you want to add to any component. for example logging:
const withLogging = Component => props => {
console.log('Props:', props);
return <Component {...props} />;
}
const List = ({ name, data }) => ...
const ListWithLogging = withLogging(List); // <-- This will log all props
-
\$\begingroup\$ I have came across this blog: css-tricks.com/what-are-higher-order-components-in-react which is using search as common component so i got confused as you said we use HOC for behaviour(not presentation) please help to understand this \$\endgroup\$Nihal Saxena– Nihal Saxena2020年04月12日 15:30:59 +00:00Commented Apr 12, 2020 at 15:30
-
1\$\begingroup\$ CSS-Tricks has some valuable resources, but I wouldn't consider the examples in that article the best use of HOCs. Take a look at the official React docs on HOCs (linked at the bottom of that article): reactjs.org/docs/higher-order-components.html - notice that none of those examples include any JSX in the HOC's
render
method other than the WrappedComponent. The HOCs in those examples are only used for behavioral/data concerns, not presentation. That said, you COULD use HOCs for presentation, but there are other patterns that would do it more clearly (like render props or hooks) \$\endgroup\$helloitsjoe– helloitsjoe2020年04月12日 18:03:38 +00:00Commented Apr 12, 2020 at 18:03