1

I have 2 components in my react application. On first time page load, the first component is supposed to make a query and display data(buttons) accordingly. The state of second component till now is empty. When the user clicks on any of the button, another request should be made to the sever and state of the second component should be changed and should be reflected on the web page. These are my files.. Apps.js

import React, { Component } from 'react';
import './App.css';

import OrgList from "./orgList"
import OrgDetails from "./orgDetails"
class App extends Component {
  
  render() {
    return [
       <OrgList/>,
       <OrgDetails/>

    ];
  }
}

export default App;
orgList.js

import React, { Component } from 'react'
import OrgDetails from "./orgDetails"
var posts =[]

 class OrgList extends Component {
   constructor(props){
     super(props);
     this.state={
     mainpost: [],
     devices:[],
     }
}
     
     componentDidMount(){
         fetch(someURL)
         .then(res => res.json())
         
         .then(function (data){
            for (let i = 0; i < 3; i++){
                posts.push(data.orgs[i].name) 
               } 

         }).then(mainpost => this.setState({mainpost:posts}));
                 
    }
  render() {
      var token =new OrgDetails();
     const postItems =this.state.mainpost.map((post) => (
      console.log(post),
      <button
        data-tech={post}
        key={post}
        className="org-btn"
        onClick={() => token.dispatchBtnAction(post)}
      >
      <h3>{post}</h3>
      </button>
      
    )
    )
    return (
      <div>
        <h3> Organisations!!!! </h3>
        <h5>{postItems}</h5>
      </div>
    )
  }
}
export default OrgList;

orgDetails.js

import React, { Component } from 'react'
var list =[]

const orgname = org =>
  `someURL/${org}`

 class OrgDetails extends Component {
     state={
         devices:[],
     }
   constructor(props){
     super(props);
     this.state={
     devices: [],
     }
     this.dispatchBtnAction=this.dispatchBtnAction.bind(this)
   }


dispatchBtnAction=(str) => {
    list =[]
    fetch(orgname(str))
    .then(res => res.json())
    
    .then(function (data){
       for (let i = 0; i < 3; i++){  
           //console.log("123")
           list.push(data.devices[i].location)
           console.log(list)  
          } 
  
    }).then(devices => this.setState({
        devices : list,
    }));
  }
   

  render() {
    const devices=this.state.devices.map((dev,i)=>(
      <div key={dev}>
      <li>{dev}</li>
      </div>
    ))
    return (
      <div>
        <p>{devices}</p>
      </div>
    )
  }
}

export default OrgDetails;

But I am getting this warning...

Warning: Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to this.state directly or define a state = {}; class property with the desired state in the OrgDetails component.

Because of this, the state is not getting changed and the component is not rerendering. How to eliminate this warning and if any better method is there please do suggest.

user304378
  • 11
  • 4
  • In `orgList` you forgot to close your constructor and therefore `componentDidMount` is inside it. One of the most important concepts is proper indentation. –  Jan 14 '19 at 11:53
  • Oh Sorry..that must have happened when I was adding my question here...In my actual code this is not the issue...I'll edit it here – user304378 Jan 14 '19 at 11:57
  • Usually what you do is pass up the click to the first component that is a common parent, then set its state. The state is then passed down to the other child via props. You can also use the relatively new [`Context`](https://reactjs.org/docs/context.html). –  Jan 14 '19 at 12:01
  • Possible duplicate of [How to pass data from child component to its parent in ReactJS?](https://stackoverflow.com/questions/38394015/how-to-pass-data-from-child-component-to-its-parent-in-reactjs) –  Jan 14 '19 at 12:02
  • @ChrisG Can u pls tell that why am I getting `Can't call setState on a component that is not yet mounted` although by using ComponentDidMount function, we find out that the component is getting mounted. – user304378 Jan 14 '19 at 12:13
  • Sorry, I can't, because I cannot reproduce the error with your code. –  Jan 14 '19 at 12:21

2 Answers2

0

As these 2 component are not parent-child components, perhaps you should implement all the logic in the App and than pass state-handlers as props to each component. Then your components will look something like this:

class App extends Component {
  state = { clicks: 0 }
  incrementState = () { 
    const prev = this.state.clicks;
    this.setState({ clicks: prev + 1 })
  }

  render() {
    return [
       <DisplayComponent counter={this.state.clicks} />,
       <ControlComponent onIncrement={this.incrementState} />

    ];
  }
}

Component that displays state

class DisplayComponent extends Component{
  render() {
    return (<h3>this.props.counter</h3>);
    }
  }

Component that handles state

class ControlComponent extends Component {
  render() {
    return (<button onClick={this.props.onIncrement}>click me</button>)
  }
}
Nikita Neganov
  • 545
  • 8
  • 22
0

Well the whole issue is this line var token =new OrgDetails(); This just creates the object. But doesn't mount it in the DOM. It also doesn't reference to the component <OrgDetails/> created in App. So when you try to use token.dispatchBtnAction(post), you are trying to setState on a component that is not mounted in the DOM, hence the error.

This is a really questionable way of making communication in between two components. You are better off using a Parent-Child relationship in between component. Also you can have a look at making Presentational Component and Container components differentiation to make the workflow easy. Have a read at the this link.

Pranay Tripathi
  • 1,614
  • 1
  • 16
  • 24