Search code examples
reactjsaxiosmobxmobx-react

Use mobx and react get an error: Too many re-renders. React limits the number of renders to prevent an infinite loop


In my mind, I want use mobx to save a state named mask, when I use axios, this state will be true and when i finshed call, this state will be false, below is my code

store.tsx

import { makeAutoObservable, runInAction } from 'mobx';
import axios from 'axios';

class Store {

isHeaderShow = false;

isTabBarShow = false;

isShowingMovies = [];

isShowingMovieIds = [];

willShowingMovies = [];

willShowingMovieIds = [];

isLoading = false;


constructor() {
    makeAutoObservable(this);
}


getShowingMovies = async () => {
    if (this.isShowingMovies.length === 0) {
        this.isLoading = true;
        let res = await axios.get(`http://localhost:3000/movie/ajax/movieOnInfoList`).then((res) => {
            return res.data;
            this.isLoading = false;
        })
        runInAction(() => {
            this.isShowingMovies = res.movieList;
            this.isShowingMovieIds = res.movieIds;
           
        })
    }
}
}

    const store = new Store();
    
    export default store

mask.tsx

import React, { useState, FC } from 'react'
import { Mask } from 'antd-mobile'
import store from '../../mobx/store'
import { observer } from 'mobx-react';

const SimpleMask: FC = () => {
    const [visible, setVisible] = useState(false)
    setVisible(store.isLoading);
    return (
        <>
            <Mask visible={visible} />
        </>
    )
}

export default observer(SimpleMask)

App.tsx

import React from 'react';
import './App.css';
import Header from './component/header'
import Footer from './component/footer'
import Mask from './component/mark'

function App() {
  return (
    <div className="container">
      <div className='header'>
        <Header />
      </div>
      <div className='main'>This is main</div>
      <div className='footer'>
        <Footer />
      </div>
      <Mask/>
    </div>
  );
}

export default App;

package.json

"dependencies": {
    "@testing-library/jest-dom": "^5.16.2",
    "@testing-library/react": "^12.1.3",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^27.4.1",
    "@types/node": "^16.11.26",
    "@types/react": "^17.0.39",
    "@types/react-dom": "^17.0.13",
    "antd-mobile": "^5.4.0",
    "axios": "^0.26.0",
    "mobx": "^6.4.2",
    "mobx-react": "^7.3.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "5.0.0",
    "typescript": "^4.6.2",
    "web-vitals": "^2.1.4"
  },

the error is below error info

Could u guys give me some advices? I'm first use react and mobx and want to improve. Thank u very much!


Solution

  • You are calling setVisible directly in your Mask component, which causes a re-render, which causes setVisible to be called again, and the infinite loop continues.

    You could make it so that you only update the state when store.isLoading actually changes with the help of useEffect:

    const SimpleMask: FC = () => {
        const [visible, setVisible] = useState(false)
        
        useEffect(() => {
          setVisible(store.isLoading)
        }, [store.isLoading])
    
        return (
            <Mask visible={visible} />
        )
    }
    

    Or you could skip the useState entirely and just use your store straight away:

    const SimpleMask: FC = () => {
        return (
            <Mask visible={store.isLoading} />
        )
    }