Search code examples
reactjsmaterial-uijotai

State management - Cannot update a component (`Provider`) while rendering a different component


I am trying to use jotai to update a global indicator. The indicator will activate the LinearProgress(true or false)

In atom.js I have created a basic atom that will serve as the indicator:

export const isDownloadAtom = atom(false)

Adding the provider to the app:

import { Provider } from "jotai";
ReactDOM.render(
<React.StrictMode>
    <Provider>
        <BrowserRouter>
            <App />
        </BrowserRouter>
    </Provider>
</React.StrictMode>,
document.getElementById("root")
);

And eventually updating the indicator:

import { Get } from 'react-axios';
import { useAtom } from "jotai";
import { isDownloadAtom } from "../store/atom";
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';


export default function Quotes() {

const [, set] = useAtom(isDownloadAtom)
const url = '/random'

return (
    <div style={{ padding: 20 }}>
        <Get url={url}>
            {(error, response, isLoading, makeRequest, axios) => {
                if (error) {
                    return (<div>Something bad happened: {error.message} <button onClick={() => makeRequest({ params: { reload: true } })}>Retry</button></div>)
                }
                else if (isLoading) {
                    set(true)
                    return (<div>Loading...</div>)
                }
                else if (response !== null) {
                    set(false)
                    return (
                        <div>

And the LinearProgress component:

  import { useAtom } from "jotai";
  import { isDownloadAtom } from "../../store/atom";
  export default function AppBar() {

  const [isDownload] = useAtom(isDownloadAtom)

  return (
    <div >
        <MuiAppBar position="static">
            <Toolbar variant="dense" color="inherit">
                <IconButton
                    edge="start"
                    color="inherit"
                    aria-label="menu"
                    to="/"
                    component={Link}
                    size="large">
                    <IconHome />
                    <Typography variant="h6">Online Information</Typography>
                </IconButton>
            </Toolbar>
            {isDownload ? <LinearProgress /> : ''}
        </MuiAppBar>
    </div>

In general the code is working but when I refreshing the page (F5) I am getting the following warning message

Warning: Cannot update a component (AppBar) while rendering a different component (Request). To locate the bad setState() call inside `Request

I would like to understand what is the issue and how can I resolved this.

Thank you


Solution

  • What is the relation of AppBar and Quotes components? Are they siblings or one is rendered conditionally? Can't really tell without seeing the whole thing, but I assume setState() inside render block is the culprit. As a general rule, React component should not cause side effects in other components during rendering. Check if passing callbacks directly on <Get> component changes anything.

    <Get url={url} onSuccess={(res) => set(false)} onLoading={() => set(true)}>
        {(error, response, isLoading, makeRequest, axios) => {
            if (error) {
                return (<div>Something bad happened: {error.message} <button onClick={() => makeRequest({ params: { reload: true } })}>Retry</button></div>)
            } else if (isLoading) {
                //set(true) - this is probably the issue
                return (<div>Loading...</div>)
            } else if (response !== null) {
                //set(false)
                return (<div>...
    

    If you could provide a minimal reproducible example it would be much easier to tell what's going on.