Reputation: 71
I have a users component that just displays a list of users. I have tried to wrap it in a HOC loading component so that it only displays once the users are loaded, otherwise shows a loading spinner (well just text for now)
this is my HOC:
const Loading = (propName) => (WrappedComponent) => {
return class extends React.Component{
render(){
return this.props[propName].length === 0 ? <div> Loading... </div> : <WrappedComponent {...this.props} />
}
}
}
export default Loading;
at the bottom of my users component I have this:
export default connect(
mapStateToProps,
mapDispatchToProps
)(Loading('users')(Users));
currently, the word Loading...
is just staying on screen. and propName
is coming through as undefined
I think for some reason the users component is never getting populated. what have i done wrong?
Upvotes: 4
Views: 102
Reputation: 17618
Update after comments
My answer below is a misleading one since I hadn't understood your intention properly at that time. Also, my explanation about not getting props
is somehow wrong. It is true if we don't render the components but here you are doing it. So, the problem was not that.
The problem here is your Loading
component isn't rendered again after fetching users. Actually, you never fetch the users :) Here are the steps of your app (probably).
Users
file but it does not export the real Users
component. This is important.Loading
one not the Users
one.Loading
your users
prop is empty, so you see Loading.... Users
component never renders again. So, fetching the users there don't update the state.Your solution is extracting the fetch out of Users
and feed this component. Probably in a parent one. So:
Loading
HOC component renders a second time.I don't know how do you plan to use this HOC but if I understood right (since I'm not so experienced with HOC) in your case the problem is you are not passing any prop
to the Loading
function. This is because you are not using it as a regular component here. It is a function and propName
here is just an argument.
When we render a stateless function like this:
<Loading propName="foo" />
then there will be a props
argument for our function. If we don't render it like that there will be no props
argument and no props.propName
. If this is wrong please somebody fix this and explain the right logic. So, you want to do something like this probably:
class App extends React.Component {
render() {
return (
<div><FooWithLoading /></div>
);
}
}
const Loading = (users) => (WrappedComponent) => {
return class extends React.Component {
render() {
return (
users.length === 0 ? <div> Loading... </div> :
<WrappedComponent
users={users}
/>
);
}
}
};
const Foo = props => {
return (
<div>
Users: {props.users}
</div>
);
}
const FooWithLoading = Loading("foobar")(Foo);
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
So in your case:
export default connect(
mapStateToProps,
mapDispatchToProps
)(Loading('users')(Users));
should work?
Or you need to render your component properly in a suitable place of your app.
Upvotes: 2