Reputation: 135
I've created the following Higher-Order Component:
const baseComponent = (WrappedComponent: React.ComponentClass<any>) => (props: IKeyValue) => {
if (props.isLoading) {
return (
<LoadingSpinnerComponent shown={true} />
);
}
return (
<WrappedComponent {...props} />
);
};
This is causing this component to be called indefinitely.
(componentDidMount
in myComponent
will, means, this component is being recreated).
I am using it in the following way:
export default connect(
mapStateToProps,
dispatchToProps,
)(baseComponent(myComponent)) as React.ComponentClass<any>;
When removing the if part:
if (props.isLoading) {
return (
<LoadingSpinnerComponent shown={true} />
);
}
The component will be called only once. I tried to debug deep inside the react lib code but the magic is a wonder for me. Any idea?
Thanks in advance!
EDIT:
The full code:
myComponent
:
class MiniCatalogContainer extends React.PureComponent<IProps, void> {
public componentDidMount() {
const { fetchCatalog} = this.props;
fetchCatalog({path});
}
public render() {
...
}
}
export default connect(
mapStateToProps,
dispatchToProps,
)(baseComponent(MyComponent)) as React.ComponentClass<any>;
promise-middleware
import { Dispatch } from 'react-portal/src/interfaces';
import isPromise from 'react-portal/src/utils/is-promise';
interface IOptions {
dispatch: Dispatch;
}
export default function promiseMiddleware({ dispatch }: IOptions) {
return (next: Dispatch) => (action: any) => {
if (!isPromise(action.payload)) {
return next(action);
}
const { types, payload, meta } = action;
const { promise, data } = payload;
const [ PENDING, FULFILLED, REJECTED ] = types;
/**
* Dispatch the pending action
*/
dispatch( { type: PENDING,
...(data ? { payload: data } : {}),
...(meta ? { meta } : {}),
});
/**
* If successful, dispatch the fulfilled action, otherwise dispatch
* rejected action.
*/
return promise.then(
(result: any) => {
dispatch({
meta,
payload: result,
type: FULFILLED,
});
},
(error: any) => {
dispatch({
meta,
payload: error,
type: REJECTED,
});
},
);
};
}
SOLUTION:
As @Shleng noticed, the loop is because of my fetch
call inside the component. I ended up with the simple solution:
const baseComponent = (WrappedComponent: React.ComponentClass<any>) => (props: IKeyValue) => {
if (props.isLoading) {
return (
<LoadingSpinnerComponent shown={true} />
<WrappedComponent {...props} />
);
}
return (
<WrappedComponent {...props} />
);
};
Upvotes: 2
Views: 1056
Reputation: 1006
Because you call fetchCatalog
inside wrapped component's componentDidMount
, so the workflow results in a loop as illustrated below:
mount WrappedComponent -> fetch -> mount Spinner -> loaded -> mount WrappedComponent -> fetch (loop!)
isLoading: false -> true -> false -> true
Upvotes: 2