I have a React component using the react-polling library to poll an endpoint. It will keep on polling till the expected response is obtained. During polling, it shows a message that polling is in progress. After polling terminates, it will show a success response.
A quick overview of the key props of the Polling component:
- onSuccess - callback that takes the axios response and returns true to continue polling and false to stop polling
- onFailure - callback called when the API/endpoint call wasn't successful.
- render - Renders content
The entire implementation is present in ReactPolling.js. Please take a quick look/skim if required (especially the render method).
Code organization
I have a main App
which renders Page1Component
. It uses the Polling
component
which uses the above ReactPolling
library. I have a prop named renderOnSuccess
of type () => JSX.Element | void
. It is a function which I call after the polling is successful. It could return
- A
JSX.Element
which is the content to be shown after the polling is completed successfully. This will be set as a state variable and will be rendered. - Return nothing - in this case, nothing will be shown after polling is successful.
Case 1 (Render success message content on same page/component): (Works fine)
I return a content from the renderOnSuccess
method and it will be shown after polling is completed.
Codesandbox code for polling success case 1.
Output would be:
Page 1
Hello I am polling
..after polling completes..
Page 1
Success
Note that the Success
message is shown from the same page/component (Page1Component
)
Case 2 (Render new page after polling) (Problematic)
In this case, I want to change the top-level component itself. So, I change to page 2 from page 1.
For this, I maintain a state variable to track the page to be rendered and change it from the renderOnSuccess
callback in App.js
.
Codesandbox code for polling success case 2.
Output in this case is
Page 1
Hello I am polling
..after polling completes..
Page 2
Page 2 content
In this case, I get a warning:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
After reading posts on SO for the above warning (example), I have added a useRef
to check if the component is still mounted or not before setting contentToBeRendered
in the Polling component and now the warning goes away.
Codesandbox code for polling warning fix
Code for fix in Polling component:
const unmounted = useRef(false);
useEffect(() => {
return () => {
unmounted.current = true;
};
}, []);
//In onSuccess
let content = props.renderOnSuccess() || null;
if (!unmounted.current) {
setContentToBeRendered(content);
}
Question:
Is this the right way to handle the warning?
The fixes recommending to use useRef
usually involve making an async call. Thus, the component could be unloaded before the call returns. But here, the call to renderOnSuccess
would never return as the parent component rendered some other page (The setContentToBeRendered
will never happen).
I'm doubtful if this is the right fix and is there still a memory leak because the call to renderOnSuccess
never returns in case 2.