22214

Passing Props from State to Child

I am getting data from a WebAPI call in my componentDidMount on my parent react component. I put the values into state.

When I render my form, I am just making custom labels with data (A component), and passing the label text, and the data to this component. (One for each field I am displaying). I pass the values from state, via props, to the child components.

But what I am finding is that my child components are rendering without data being populated... as this seems to happen before the api call happens. The api happens, the state gets set, but data never gets to the child components. I thought that the props would pass the updated state data to the components. I'm wrong. How should I achieve this? I want to load the data in my parent, and then render the child components, passing in the data.

componentDidMount() { this.loadData(); } loadData() { var request = { method: 'GET', URL: "http://example.com/api/user/profile", } fetchData(request).then(response => { if(response.errorcode != "OK") { console.log("Bad response from API. Need to redirect!") } else { this.setState( { firstname: response.payload.firstname, surname: response.payload.surname, email: response.payload.email, countryId: response.payload.countryId, countries: response.payload.countries } ); } }); } render() { return ( <div> <h2>Your Profile</h2> <div className="row"> <div className="col-xs-6"> <DisplayLabel labelText={"Firstname"} data={this.state.firstname} /> <DisplayLabel labelText={"Surname"} data={this.state.surname} /> <DisplayLabel labelText={"Email Address"} data={this.state.email} /> <DisplayLabel labelText={"Country"} data={this.state.countryId} /> <div className="form-group row right"> <button className="btn btn-primary" onClick={this.openModal}>Edit</button> </div> </div> </div> <Modal isOpen={this.state.modalIsOpen} onAfterOpen={this.afterOpenModal} style={modalStyle}> <ProfileEditBox closeMeCallback = {this.closeModal} /> </Modal> </div> ) }

My display label component is simply this. I'm new to this, and just trying to make reusable components:

import React, {Component} from 'react'; export default class DisplayLabel extends Component { constructor(props) { super(props); this.state = { labelText: this.props.labelText, data: this.props.data } console.log(this.state); } componentDidMount() { this.setState({ labelText: this.props.labelText, data: this.props.data }); console.log("ComponentDidMount", this.state); } render() { return ( <div> <div className="row"> <div className="col-xs-12"> <label className="control-label">{this.state.labelText}</label> </div> </div> <div className="row"> <div className="col-xs-12"> &nbsp;&nbsp;<strong><span>{this.state.data}</span></strong> </div> </div> </div> ) } }

I need to wait for the API call to complete before I render the form?

Answer1:

I'm not sure you have to wait until the request complete (but you most likely do have to for UI issues), but i guess your problem is something else.

you took the props and included them inside your state (that's unneccery), and then when the component complete it's loading you update the state again, but the request probbaly compleate after the componnent complete it's loading.

if you must to put the props inside your state, you should add componentDidUpdate or componentWillReceiveNewProps lifecycle functions, not the componentDidMount.

but, if you don't have to (most likley), you might change your render funcion to:

render() { return ( <div> <div className="row"> <div className="col-xs-12"> <label className="control-label">{this.props.labelText}</label> </div> </div> <div className="row"> <div className="col-xs-12"> &nbsp;&nbsp;<strong><span>{this.props.data}</span></strong> </div> </div> </div> ) }

(just changed the state to props)

Try that, Good Luck!

Answer2:

This is a common problem in React. I usually try to resolve it with a pattern that shows some sort of loading indicator. So I would initialize your state like this in the constructor:

this.state = { loading: true }

And I would change your render to have a check for that loading bool:

render() { if (this.state.loading) { return (<h1>Loading, please wait...</h1>); } return ( <div> <h2>Your Profile</h2> <div className="row"> <div className="col-xs-6"> <DisplayLabel labelText={"Firstname"} data={this.state.firstname} /> <DisplayLabel labelText={"Surname"} data={this.state.surname} /> <DisplayLabel labelText={"Email Address"} data={this.state.email} /> <DisplayLabel labelText={"Country"} data={this.state.countryId} /> <div className="form-group row right"> <button className="btn btn-primary" onClick={this.openModal}>Edit</button> </div> </div> </div> <Modal isOpen={this.state.modalIsOpen} onAfterOpen={this.afterOpenModal} style={modalStyle}> <ProfileEditBox closeMeCallback = {this.closeModal} /> </Modal> </div> ) }

Then you can set loading to false following a successful data pull, and your form will display correctly without any errors.

(I edited this to use your parent component rather than DisplayLabel, as it makes more sense there. However, the component name is omitted from your question).

Answer3:

Just because constructor called once when component mount so you can do one thing, in your render take two var and assign data into that. And then use those variable to show data. Because child component will render Everytime state of parent will change but constructor will not.

Recommend

  • Setting default selected value of selectlist inside an editor template
  • Why is this Exception?- The relationship between the two objects cannot be defined because they are
  • DropDownList not behaving as expected
  • How to assign a prop value to a state in react
  • Propertygrid UIEditor disabling value editing through Keyboard
  • Working with EditorTemplates and radio buttons
  • How to orderByValue onSnapshot using Firestore
  • Get Distinct Parent Items using Lambda
  • Script to update a column
  • Passing property list as strongly typed parameters
  • Globalized custom number formatting - Variable decimal points
  • MySQL performance using AUTO_INCREMENT on a PRIMARY KEY
  • React 16 Error Boundary component (using componentDidCatch) shows uncaught error
  • Cannot read property setState of undefined in axios callback
  • Creating a Messenger service
  • Fatal error: Call to a member function fetch() on a non-object?
  • How to import these postal codes into a normalized table?
  • Retrieve Facebook Account Information in ios 6
  • Get current user from inside the model in Sails
  • Mocha throws unexpected token error for ES6 object spread operator
  • Ionic storage “get” returns null only on the second call within method
  • pip in virtualenv gets ConnectTimeoutError
  • didUpdatePushCredentials not get called
  • Element.tagName for python not working
  • How do I access an unhandled exception in an MVC Error view?
  • How to attach a node.js readable stream to a Sendgrid email?
  • Email verification using google app script and google forms
  • Bad request using file_get_contents for PUT request in PHP
  • Email format validation in mvc3 view
  • Dynamically accessing properties of knockoutjs observable array
  • sending/ receiving email in Java
  • Hazelcast - OperationTimeoutException
  • RestKit - RKRequestDelegate does not exist
  • Revoking OAuth Access Token Results in 404 Not Found
  • Codeigniter doesn't let me update entry, because some fields must be unique
  • need help with bizarre java.net.HttpURLConnection behavior
  • Django query for large number of relationships
  • Why is Django giving me: 'first_name' is an invalid keyword argument for this function?
  • How can I use `wmic` in a Windows PE script?
  • How to push additional view controllers onto NavigationController but keep the TabBar?