react warning cannot set state when using promises

前端 未结 7 1314
情深已故
情深已故 2020-12-19 13:40

I\'m trying to query the server to get list of nav items so I can build my menu on init. I\'ve so far managed to create a static page with 3 contents on the home page, which

相关标签:
7条回答
  • 2020-12-19 14:22

    try to check if the componenet mounted before you update:

    import React, { Component } from 'react';
    import ReactDOM from 'react-dom';
    
    import SideBar from './components/sidebar';
    import Header from './components/header';
    import HomeContent from './components/home';
    
    class App extends Component {
        constructor(props){
            super(props);
            this.mountCheck = false;
            this.state = { navlist: [] };
        }
    
        componentWillMount() {
            this.mountCheck = true;
        }
        componentWillUnmount() {
            this.mountCheck = false;
        }
    
        componentDidMount() {
             $.get('/api/user/get/user/method/menu/format/json')
            .done(( response ) => this.setState({ navlist: response } ));
        }
    
        render() {
            return (
                <div>
                    <Header />
                    <SideBar navlist={this.state.navlist}/>
                    <HomeContent />
                </div>
            );
        }
    };
    
    ReactDOM.render(<App/>,  document.getElementById("app"));
    

    also you can add shouldComponentUpdate to improve performance and reduce wastful rendering e.g:

    shouldComponentUpdate(nextProps, nextState) {
        if (this.state.navlist !== nextState.navlist) {
          return true;
        }
        return false;
      }
    

    see https://reactjs.org/docs/optimizing-performance.html

    deep compare check for better performance results you can use it with isEqual's lodash :

    shouldComponentUpdate(nextProps, nextState) {
            return !isEqual(this.state, nextState);
          }
    
    0 讨论(0)
  • 2020-12-19 14:23

    I would move the logic of your get request into componentWillMount. The React error is telling you that the promise can only be called in a "Mounting component". Then you can call setState. Then in your render you can conditionally render based on the state variable.

    {this.state.navList.length &&
             <div>
                <Header />
                <SideBar navlist={this.state.navlist}/>
                <HomeContent />
            </div>}
    

    You can also render a different loading component while you wait for the data to return.

    0 讨论(0)
  • 2020-12-19 14:25

    You will try this

         fetch(url)
            .then((response) => {
                   let jsonData=response.json();
                   this.setState({data:jsonData})
             })
            .catch((error) => {
                   console.log("error---",error);
             })
    
    0 讨论(0)
  • 2020-12-19 14:38
    import React, { Component } from 'react';
    import ReactDOM from 'react-dom';
    import SideBar from './components/sidebar';
    import Header from './components/header';
    import HomeContent from './components/home';
    
    class App extends Component {
        constructor(props){
            super(props);
            this.state = { navlist: [] };
        }
    
      componentDidMount() {
             $.get('api/call')
            .then(( response ) => this.setState({ navlist: response } ));
        }
    
        render() {
            return (
                <div>
                    <Header />
                    <SideBar navlist={this.state.navlist}/>
                    <HomeContent />
                </div>
            );
        }
    };
    
    ReactDOM.render(<App/>,  document.getElementById("app"));
    
    0 讨论(0)
  • 2020-12-19 14:39

    You have a setState in your componentDidMount. That creates a loop where your component will keep mounting itself forever (since setState eventually leads to componentDidMount being called), which is why React prevents it. The data you get through getJSON should only update the state, not be passed on to one of React's rendering phases. When the state is updated, then your component should re-render automatically. Most of the logic you have in componentDidMount should be in your render function, formatting the data so it can then be used by the return command below.

    0 讨论(0)
  • 2020-12-19 14:39

    seems like the issue was separating the code properly in different files. I had index, App with componentDidMount() all in one which was not working.

    so i have done

    index

    import React, { Component } from 'react'
    import ReactDOM from 'react-dom'
    import { Provider } from 'react-redux';
    import { createStore, applyMiddleware, combineReducers } from 'redux';
    import { BrowserRouter, Route, browserHistory } from 'react-router-dom';
    import promise from 'redux-promise';
    
    import App from './App'
    import reducers from './reducers';
    
    require("babel-core/register");
    require("babel-polyfill");
    
    const createStoreWithMiddleware = applyMiddleware(promise)(createStore);
    
    ReactDOM.render(
            <Provider store={createStoreWithMiddleware(reducers)}>
                <BrowserRouter history={browserHistory}>
                    <App/>
                </BrowserRouter>
            </Provider>
            , document.getElementById('root'));
    

    App

    import React, { Component } from 'react'
    import { HashRouter, Switch, Route, Link } from 'react-router-dom';
    import Header from './components/header';
    import Logout from './components/logout';
    import SideBar from './components/sidebar';
    import HomeContent from './components/home';
    import Ldapuser from './components/ldapuser';
    import AdminContent from './components/getting_started/admin';
    
    const Main = () => (
        <main>
         <Switch>
           <Route exact path='/index.html' component={HomeContent}/>
           <Route exact path='/home' component={HomeContent}/>      
           <Route path='/logout' component={Logout}/>
           <Route path='/ldapuser' component={Ldapuser}/>
           <Route path='/admin/content' component={AdminContent}/>
         </Switch>
        </main>
    )
    
    class App extends Component {
    
        render() {
            return (
                <div>
                    <Header />
                    <SideBar />
                    <Main />
                 </div>
            );
        }
    }
    
    export default App;
    

    and the individual files... header etc will have componentDidMount() which now works

    0 讨论(0)
提交回复
热议问题