0

I'm trying to update an object array namely users inside Users component, using following function:

  updateUser = (index, user) => {
    let temp = this.state.users;
    temp[index] = user;
    this.setState({users: temp});
    console.log(this.state.users);
    console.log(temp);
  }        

Doing that gives me following warning:

proxyConsole.js:56 Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the Users component.

Log output is as follows:
enter image description here

Please Note:

  • This function is called from another component to update a single user from an array of user. But the value is not persisting . As soon as I call this function with another/new value old updates doesn't retains.
  • My objective is to re-render all the components as soon as array is modified.
    Edit1: I have four components: IE. Users component is calling List it is calling User and it is calling UserDetail.

Users component:

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

class Users extends Component {
  constructor(){
    super();
    this.state = {
      users:[
        {firstName: "John", lastName: "Doe", email: "John@mail.com", company: "Monsters Inc."},
        {firstName: "Tom", lastName: "Riddle", email: "Tom@mail.com", company: "Slytherin Inc."},
        {firstName: "Harry", lastName: "Potter", email: "Harry@mail.com", company: "Gryffindor Inc."}
      ],
      adding: false
    }
  }

  updateUser = (index, user) => {
    let temp = this.state.users;
    temp[index] = user;
    this.setState({users: temp});
    console.log(this.state.users);
    console.log(temp);
  }

  render() {
    return (
        <div>
          <button onClick={this.addingMode}>ADD</button>
          <List data={this.state.users} remover={this.remover} updateUser={this.updateUser}/>
        </div>
      );
    }
}

export default Users;

List component:

class List extends Component {
  render() {
    return (
      <div style={{textAlign:"Left"}}>
        {this.props.data.map((profile, i) =>
          <User key={i} id={i} data={profile} remover={this.props.remover} updateUser={this.props.updateUser}/>
        )}
      </div>
    );
  }
}

User component:

import React, { Component } from 'react';
import '../App.css';
import UserDetails from './userDetails';
import {withRouter} from 'react-router';

class User extends Component {
  constructor(props){
    super(props);
    this.state = {
      editing: false,
      text: ""
    };
  };

  showUserDetails = () => {
    this.props.history.push({
      pathname: '/details',
      state: { data: this.props.data, id: this.props.id },
      updateUser: this.props.updateUser
    });
  };

  render() {
    return(
    <div>
      <h4>{this.props.data.firstName}</h4>
      <button onClick={this.showUserDetails}>View</button>
      <button>Remove</button>
    </div>
    );
  }
}

export default withRouter(User);          

UserDetails component:

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

class UserDetails extends Component {
  constructor(props){
    super(props);
    this.state = {
      isEditModeEnabled: false,
      firstName: this.props.location.state.data.firstName,
      lastName: this.props.location.state.data.lastName,
      email: this.props.location.state.data.email,
      company: this.props.location.state.data.company
    };
  }

  editButton = () => {
    this.setState({isEditModeEnabled: true});
  }

  updateButton = () => {
    this.setState({isEditModeEnabled: false});
    //console.log(this.props.location);
    this.props.location.updateUser(
      this.props.location.state.id,
      { "firstName": this.state.firstName,
        "lastName": this.state.lastName,
        "email": this.state.email,
        "company": this.state.company
      }
    );
  }

  editing = (event) => {
    if (event.target.name === "firstName") {
      this.setState({firstName: event.target.value});
    } else if (event.target.name === "lastName") {
      this.setState({lastName: event.target.value});
    } else if (event.target.name === "email") {
      this.setState({email: event.target.value});
    } else {
      this.setState({company: event.target.value});
    }
  }

  render() {
    if (this.state.isEditModeEnabled) {
      return (
        <div>
          <b>First Name: </b><textarea defaultValue={this.state.firstName} onChange={this.editing} name="firstName"></textarea><br/>
          <b>Last Name: </b><textarea defaultValue={this.state.lastName} onChange={this.editing} name="lastName"></textarea><br/>
          <b>Email: </b><textarea defaultValue={this.state.email} onChange={this.editing} name="email"></textarea><br/>
          <b>Company: </b><textarea defaultValue={this.state.company} onChange={this.editing} name="company"></textarea><br/>
          <button onClick={this.updateButton}>Update</button>
        </div>
      );
    } else {
      return (
        <div>
          <b>First Name: </b>{this.props.location.state.data.firstName}<br/>
          <b>Last Name: </b>{this.props.location.state.data.lastName}<br/>
          <b>Email: </b>{this.props.location.state.data.email}<br/>
          <b>Company: </b>{this.props.location.state.data.company}<br/>
          <button onClick={this.editButton}>Edit</button>
        </div>
      );
    }
  }
}

export default UserDetails;
noobie
  • 751
  • 4
  • 13
  • 33

1 Answers1

-2

It might be because setState is asynchronous. That means a console.log() right after a setState gives you false information. Use the callback function of setState to determine state changes:

this.setState({users: temp}, () => console.log(this.state.users));

You should share more of your component to determine the real issue you are facing. It's hard to tell what you are really trying to do, since the code snippet you shared points to a asynchronous issue, while your description and warnings point to another.

Nocebo
  • 1,927
  • 3
  • 15
  • 26
  • I didn't down voted it. But I already know **setState is asynchronous**. Kindly see the screenshot it shows the updated state. – noobie Sep 26 '17 at 09:43
  • @noobie Oh it seemed like you didn't (`console.log(this.state.users);)`. I couldn't determine the workflow of your app from a single screenshot and assumed it showed the old `state`, sorry for that. I can't tell what you are doing wrong from your updated code though, sorry. – Nocebo Sep 26 '17 at 09:56