Reaction alert cannot set state when using promises

I am trying to query the server for a list of navigational elements so that I can create my menu in init. So far, I have managed to create a static page with 3 contents on the main page, which includes the title, sidebar and content. The sidebar is a menu that is different for different types of users, so I need to get menu items at boot time.

The error I get is

It can only update a mounted or mounting component. This usually means that you called setState, replaceState, or forceUpdate on an unmounted component. It is not op

Update 4

so I moved my api requests to the index.js file and tried to add the condition specified in the comment . Now it just displays Loading... with the same error

  import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import 'core-js/fn/promise'; import SideBar from './components/sidebar'; import Header from './components/header'; import HomeContent from './components/home'; function getJSON(url) { return get(url).then(JSON.parse); } function get(url) { // Return a new promise. return new Promise(function(resolve, reject) { // Do the usual XHR stuff var req = new XMLHttpRequest(); req.open('GET', url); req.onload = function() { // This is called even on 404 etc // so check the status if (req.status == 200) { // Resolve the promise with the response text resolve(req.response); } else { // Otherwise reject with the status text // which will hopefully be a meaningful error reject(Error(req.statusText)); } }; // Handle network errors req.onerror = function() { reject(Error("Network Error")); }; // Make the request req.send(); }); } class App extends Component { constructor(props){ super(props); this.state = { username: '', user, loading1: true , menuList : [], loading2: true }; } componentDidMount() { let currentComponent = this; getJSON('/api/user/get/user/method/user/format/json?quiet=1').then((response) => { //console.log(JSON.stringify(response)); //currentComponent.state.username = response.body.recordset.record[0].name; //currentComponent.state.user = response.body.recordset.record[0]; currentComponent.setState({ username: response.body.recordset.record[0].name, loading1: false }); }).catch(error => { console.log('Error', error); }); getJSON('/api/user/get/user/method/menu/format/json?quiet=1').then((response) => { console.log(JSON.stringify(response)); let menuData = response.body.recordset.record; let menuList = []; var i = 0; menuData.container.forEach(menus => { menus.sub_modules.forEach(submenu => { menuList.push(<li className="menu" key={i}>{ submenu.title }</li>); i++ if (submenu.menuitem.length) { submenu.menuitem.forEach(menuitem => { menuList.push(<li key={i}><a href={menuitem.link}>{ menuitem.title }</a></li>); i++; }) } }) }); currentComponent.setState({ menuList: menuList, loading2: false }); }).catch(error => { console.log("Failed!", error); $('#myModalError .modal-body').html(error); $('#myModalError').modal('show'); }); } componentWillUnmount() {} render() { let content = ''; console.log(this.state); if(this.state.loading1 || this.state.loading2) { content = <div>Loading...</div> }else{ content = <div id="wrapper" className="toggled"> <Header username={this.state.username}/> <SideBar menuList={this.state.menuList}/> <HomeContent /> </div> } return <div> {content} </div> } }; ReactDOM.render(<App/>, document.getElementById("app")); 

enter image description here

here is IE error

IE Console Error

in detail, i.e. error

sidebar.js

 import React, { Component } from 'react'; let menuList = []; class SideBar extends Component { constructor(props){ super(props); } render () { return ( <div id="sidebar-wrapper" className="hidden-print"> <ul className="sidebar-nav"> {this.props.menuList} </ul> </div> ); } } export default SideBar; 

I created jsfiddle

Webpack

 var HTMLWebpackPlugin = require('html-webpack-plugin'); var HTMLWebpackPluginConfig = new HTMLWebpackPlugin({ template: __dirname + '/app/index.html', filename: 'index.html', inject: 'body' }); const ExtractTextPlugin = require("extract-text-webpack-plugin"); const extractSass = new ExtractTextPlugin({ filename: "[name].[contenthash].css", disable: process.env.NODE_ENV === "development" }); module.exports = { entry : [__dirname + '/app/index.js'], module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } , { test: /\.scss$/, use: [{ loader: "style-loader" }, { loader: "css-loader" }, { loader: "sass-loader", }] } ], }, output: { filename: 'transformed.js', path: __dirname + '/docs' }, plugins: [ HTMLWebpackPluginConfig ] } { "name": "ccp-react", "version": "1.0.0", "license": "MIT", "scripts": { "start": "webpack-dev-server", "build": "webpack" }, "private": true, "dependencies": { "babel-helper-bindify-decorators": "^6.24.1", "babel-plugin-lodash": "^3.3.2", "babel-plugin-syntax-dynamic-import": "^6.18.0", "babel-plugin-syntax-flow": "^6.18.0", "babel-plugin-transform-class-properties": "^6.24.1", "babel-plugin-transform-decorators": "^6.24.1", "babel-plugin-transform-react-display-name": "^6.25.0", "babel-plugin-transform-react-jsx": "^6.24.1", "babel-polyfill": "^6.26.0", "babel-preset-env": "^1.6.1", "babel-preset-es2015": "^6.24.1", "babel-preset-es2016": "^6.24.1", "babel-preset-es2017": "^6.24.1", "babel-preset-flow": "^6.23.0", "babel-preset-react-optimize": "^1.0.1", "babel-preset-stage-1": "^6.24.1", "babel-preset-stage-3": "^6.24.1", "bootstrap": "^3.3.7", "classnames": "^2.2.5", "commander": "^2.12.2", "create-react-class": "^15.6.2", "cross-env": "^5.1.3", "gulp": "^3.9.1", "hammerjs": "^2.0.8", "lodash": "^4.17.4", "ng": "0.0.0-rc6", "ng-cli": "^0.7.0", "react": "^16.2.0", "react-dom": "^16.2.0", "react-icons-kit": "^1.0.7", "react-redux": "^5.0.6", "react-router": "^4.2.0", "react-router-dom": "^4.2.2", "react-side-bar": "^0.3.5", "react-sidenav": "^2.1.2", "redux": "^3.7.2", "rxjs": "^5.5.6", "systemjs": "^0.20.19", "web-animations-js": "^2.3.1", "zone.js": "^0.8.19" }, "devDependencies": { "@types/jasmine": "~2.5.53", "@types/jasminewd2": "~2.0.2", "@types/node": "^6.0.95", "babel-core": "^6.26.0", "babel-loader": "^7.1.2", "babel-preset-react": "^6.24.1", "core-js": "^2.5.3", "css-loader": "^0.28.8", "extract-text-webpack-plugin": "^3.0.2", "html-webpack-plugin": "^2.30.1", "jasmine-core": "~2.6.2", "jasmine-spec-reporter": "~4.1.0", "karma": "~1.7.0", "karma-chrome-launcher": "~2.1.1", "karma-cli": "~1.0.1", "karma-coverage-istanbul-reporter": "^1.3.3", "karma-jasmine": "^1.1.1", "karma-jasmine-html-reporter": "^0.2.2", "node-sass": "^4.7.2", "protractor": "~5.1.2", "sass-loader": "^6.0.6", "style-loader": "^0.19.1", "ts-node": "~3.2.0", "tslint": "~5.7.0", "typescript": "~2.4.2", "webpack": "^3.10.0", "webpack-bundle-analyzer": "^2.8.2", "webpack-dev-server": "^2.9.7" } } 

the setstate problem still exists even with the same code as in the script. the violin works

setstate

+5
source share
7 answers

it seems like the problem was to correctly separate the code in different files. I had an index , App with componentDidMount() all in one that didn't work.

so i did

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')); 

applications

 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 individual files ... header , etc. will have componentDidMount() , which now works

0
source

try to check if the component component is installed before the upgrade:

 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")); 

you can also add shouldComponentUpdate to increase performance and reduce unnecessary rendering, for example:

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

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

to compare results with higher efficiency you can use it with isEqual lodash:

 shouldComponentUpdate(nextProps, nextState) { return !isEqual(this.state, nextState); } 
+4
source
 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")); 
+2
source

Note. I added a 2 second timeout to simulate an API call. therefore, the results will be visible after 2 seconds

 const jsonResponse = { header: { title: "CCP", description: "", error: true, message: "Method getMenu Not Implemented in CCP\\Controller\\UserController", user: "UddinS2", nav: { container: [ { title: "Users", link: "#", theme: "#007c92", sub_modules: [ { title: "Getting Started", link: "#", theme: "#007c92", menuitem: [ { title: "File - CM Template v6.3", link: "/library/templates/FW-LB-CommsMatrix-Template-v6.3.xls" }, { title: "File - Request Access", link: "/library/docs/Requesting_Access_to_CCP.pdf" }, { title: "Video - CCP Promo", link: "/video_ccp.html" }, { title: "Video - CCP Demo", link: "/video_ccp_demo.html" }, { title: "Video - Request Access", link: "/video_request_access.html" }, { title: "Video Tutorials", link: "/video_tutorials.php" } ] }, { title: "General", link: "#", theme: "#007c92", menuitem: [ { title: "DC Standard Networks", link: "/api/user/dcsn/format/xml" }, { title: "Find Comms Matrix Flow", link: "/find_comms_matrix_flow.php" }, { title: "Find Host", link: "/find_host.php" }, { title: "Find IP Network", link: "/find_network.php" }, { title: "List Comms Matrices", link: "/comms_matrices.php" }, { title: "My Exemption Requests", link: "/api/user/exemption/requests/format/xml" }, { title: "Request Exemption", link: "/request_exemption.php" }, { title: "Services, Projects, ...", link: "/api/user/services/format/xml" }, { title: "View FW Objects", link: "/view_network_service_objects.php" }, { title: "Create Comms Matrix", link: "/create_comms_matrix.php" }, { title: "Comms Matrix Templates", link: "/api/user/commsmatrix/templates" }, { title: "Upload Comms Matrix", link: "/upload_comms_matrix.php" }, { title: "Verify Policy Flow", link: "/verify_policy_flow.php" }, { title: "View Security Policy", link: "/security_zoning_policy.php" }, { title: "View Routing Policy", link: "/routing_domain_policy.php" } ] }, { title: "IP Management", link: "#", theme: "#007c92", menuitem: [ { title: "Adressing Types", link: "/api/user/iam/addressing/types/format/xml" }, { title: "Cramer Ranges (Live)", link: "/api/user/iam/cramer/ranges/format/xml" }, { title: "Cramer Spool Queue", link: "/api/user/cramer/spool/queue/format/xml" }, { title: "Create Subnet", link: "/iam_create_subnet.php" }, { title: "Subnet Types", link: "/api/user/iam/subnet/types/format/xml" }, { title: "Zone Type Sizes", link: "/api/user/security/zone/type/sizes/format/xml" }, { title: "My Network Diagrams", link: "/api/user/iam/network/diagrams/format/xml" }, { title: "My Subnet Requests", link: "/api/user/subnet/requests/format/xml" }, { title: "Range Assignments", link: "/api/user/iam/range/assignments/format/xml" }, { title: "Upload Network Diagram", link: "/iam_upload_diagram.php" } ] }, { title: "Networks", link: "#", theme: "#007c92", menuitem: [ { title: "Entity Networks", link: "/api/user/networks/by/entity/format/xml" }, { title: "Frozen Objects", link: "/api/user/frozen/objects/format/xml" }, { title: "IPBB Metadata", link: "/api/user/ipbb/metadata/format/xml" }, { title: "Map Routing Zones", link: "/api/user/routing/domains/mapping/routingzone/format/xml" }, { title: "NITX Trace", link: "/nitx_trace.php" }, { title: "Routing Domains", link: "/api/user/routing/domains/format/xml" }, { title: "Routing Domain Aliases", link: "/api/user/aliases/routing/domains/format/xml" }, { title: "Routing Domains ACL", link: "/api/user/routing/domains/acl/format/xml" }, { title: "Routing Exemptions", link: "/api/user/routing/exemptions/format/xml" } ] }, { title: "Reporting", link: "#", theme: "#007c92", menuitem: [ { title: "Statistics Dashboard", link: "/statistics_dashboard.php" }, { title: "ECT Statistics", link: "/api/user/connectivity/test/statistics" }, { title: "Exemption Requests", link: "/api/user/report/exemption/requests/format/xml" }, { title: "Exemption Policies", link: "/api/user/report/exemption/policies/format/xml" } ] }, { title: "Security", link: "#", theme: "#007c92", menuitem: [ { title: "Firewall Network Objects", link: "/firewall_network_objects.php" }, { title: "Firewall Service Objects", link: "/firewall_service_objects.php" }, { title: "Local Market Networks", link: "/api/user/networks/opco/format/xml" }, { title: "Security Exemptions", link: "/api/user/exemptions/format/xml" }, { title: "Security Zones", link: "/api/user/security/zones/format/xml" }, { title: "Security Zone Aliases", link: "/api/user/aliases/security/zones/format/xml" }, { title: "Network Zone Aliases", link: "/api/user/aliases/network/zones/format/xml" }, { title: "Map Security Zones", link: "/api/user/security/zones/mapping/seczone/format/xml" }, { title: "Map Network Zones", link: "/api/user/security/zones/mapping/netzone/format/xml" }, { title: "Security Zones ACL", link: "/api/user/security/zones/acl/format/xml" } ] }, { title: "Audit", link: "#", theme: "#007c92", menuitem: [ { title: "Firewall Network Objects", link: "/api/user/audit/firewall/network/objects/format/xml" }, { title: "Firewall Service Objects", link: "/api/user/audit/firewall/service/objects/format/xml" }, { title: "Security Zones", link: "/api/user/audit/security/zones/format/xml" }, { title: "Security Zones ACL", link: "/api/user/audit/security/zones/acl/format/xml" }, { title: "Security Zones Aliases", link: "/api/user/audit/security/zone/aliases/format/xml" }, { title: "Security Zone Mappings", link: "/api/user/audit/security/zone/mapping/format/xml" }, { title: "Network Zone Aliases", link: "/api/user/audit/network/zone/aliases/format/xml" }, { title: "Routing Domains", link: "/api/user/audit/routing/domains/format/xml" }, { title: "Routing Domains ACL", link: "/api/user/audit/routing/domains/acl/format/xml" }, { title: "Routing Domain Aliases", link: "/api/user/audit/routing/domain/aliases/format/xml" }, { title: "Routing Domain Mappings", link: "/api/user/audit/routing/domain/mapping/format/xml" } ] } ] }, { title: "Site Administration", link: "#", theme: "#007c92", sub_modules: [ { title: "Content Management", link: "#", theme: "#007c92", menuitem: [ { title: "Business Units", link: "/api/user/businessunits/format/xml" }, { title: "Entities", link: "/api/user/entities/format/xml" }, { title: "Locations", link: "/api/user/locations/format/xml" }, { title: "Markets", link: "/api/user/markets/format/xml" }, { title: "Service Domains", link: "/api/user/servicedomains/format/xml" } ] }, { title: "Health Check", link: "#", theme: "#007c92", menuitem: [ { title: "Networks Status", link: "/api/user/networks/status/format/xml" } ] }, { title: "User Management", link: "#", theme: "#007c92", menuitem: [ { title: "Assign Group Privilges", link: "/assign_group_privs.php" } ] }, { title: "Troubleshooting", link: "#", theme: "#007c92", menuitem: [ { title: "Debug Comms Matrix", link: "/debug_comms_matrix.php" }, { title: "Mocha Tests", link: "/testrunner.php" } ] }, { title: "Super Admin", link: "#", theme: "#007c92", menuitem: [ { title: "Sudo Group Access", link: "/sudo_group_access.php" } ] } ] } ] }, server: 1, version: "17.1", timestamp: 1514902917 }, body: [] }; class App extends React.Component { constructor(props) { super(props); this.state = { navList: [] }; } componentDidMount() { //$.get('/api/user/get/user/method/menu/format/json') //.done ((response) => console.log(response)); //.done(( response ) => this.setState({ navlist: //response } )); //dont have actual api hence setting state with response data mentioned in question setTimeout(() => { this.setState({ navList: jsonResponse }); }, 2000); } componentWillUnmount() {} render() { //removing header and HomeContent as definition is not there return ( <div> <SideBar navlist={this.state.navList} />{" "} </div> ); } } let SideBar = props => { const { navlist } = props; let navlistView = null; const getMenuItems = menuItemsArray => ( <ul> {" "} {menuItemsArray.map((element, index) => ( <li key={index}>{element.title} </li> ))} </ul> ); const getSubMenu = subMenuArray => ( <div> {" "} {subMenuArray.map((element, index) => ( <ul key={index}>-- - {element.title} { <li> {getMenuItems(element.menuitem)} </li> } </ul> ))} </div> ); const getView = () => { let navlistView = null; if (navlist.header) { const navInfo = navlist.header.nav.container; navlistView = navInfo.map((navlist, index) => ( <div key={index}> {navlist.title} <div> {getSubMenu(navlist.sub_modules)} </div> </div> )); } return navlistView; }; return ( <div id="sidebar-wrapper" className="hidden-print"> {" "} {getView()}{" "} </div> ); }; ReactDOM.render(<App />, document.getElementById("app")); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script> <div id="app"></div> 
 For first error Failed! TypeError: Cannot read property 'setState' of undefined issue : callback doesnot have correct context. Failed! TypeError: Cannot read property 'menuList' of undefined This is also context issue as getJson is called with new context. 

I am working on linux os, do not have IE, so I have not tested IE. I used the index as keys because I do not have a unique identifier. Check which unique identifier you can set as keys.

+2
source

You have setState in componentDidMount . This creates a loop in which your component will be permanently mounted forever (since setState ultimately leads to calling componentDidMount ), so React prevents it. The data that you get through getJSON should only update the state, and not go to one of the rendering phases. When the state is updated, your component should automatically redraw. Most of the logic that you have in componentDidMount should be in your render function, formatting the data so that it can then be used with the return command below.

0
source

You will try it

  fetch(url) .then((response) => { let jsonData=response.json(); this.setState({data:jsonData}) }) .catch((error) => { console.log("error---",error); }) 
0
source

I would move the logic of your receive request to componentWillMount. A React error tells you that a promise can only be invoked in the "Mounting Component". Then you can call setState. Then in the render you can conditionally display based on a state variable.

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

You can also display another download component while you wait for data to return.

0
source

Source: https://habr.com/ru/post/1274441/


All Articles