Raúl C. Rivero
Raúl C. Rivero

Reputation: 297

React undefined setState from props

I've two componentes: Orders and FormDialog, the first is father of the second. I've trying to send data as properties from Orders to FormDialog as follows:

Orders Component

class Orders extends Component {
 state={
    open: false,
    order: {
      address: '',
      client: '',
      date: '',
      estimated_time: '',
      id: 0,
      order_no: '',
      original_order_no: '',
      phone: '',
      place: '',
      position: '',
      status: '',
      team: ''
    }
  }
 render() {
    return (
      <div>
        <FormDialog open={this.state.open} order={this.state.order}/>
      </div>
    );
  }

FormDialog Component

export default class FormDialog extends React.Component {

  constructor(...props) {
    super(...props);
    this.state = {
      order: {
        address: '',
        client: '',
        date: '',
        estimated_time: '',
        id: 0,
        order_no: '',
        original_order_no: '',
        phone: '',
        place: '',
        position: '',
        status: '',
        team: ''
      }
    };
  }
  async componentWillMount()
    this.setState({order: this.props.order})
  };
  render() {
    return (
      <div>{this.state.order.team}</div>
  )}

This display TypeError: this.state.order is undefined when try to compile. Any suggestion?

Upvotes: 1

Views: 2631

Answers (3)

ToneCrate
ToneCrate

Reputation: 544

Two issues:

  1. Your render method is trying to render a FormDialog using state which isn't initialized yet. State will be undefined until you set it inside constructor like:

    constructor(props) {
        super(props);
    
        this.state = {
            order: this.props.order,
        }
    }
    

Since you're just passing down a prop from the parent component, this will be enough to render the component without errors. This way you don't need to call componentDidMount or, in your case, componentWillMount, and can remove it altogether.


  1. You're calling setState in an unmounted component, which will always result in an error in React. As its name suggests, componentWillMount is called right before the component mounts and you should be using componentDidMount instead to make sure the component is mounted before calling setState.

Also, componentWillMount has been deprecated in newer versions of React and is no longer recommended to be used in code.

From React official documentation


Additional note, it seems to me that you have unnecessary duplication of state in these two components. Consider keeping the order data only in the FormDialog component since it will probably be the only component updating order data.

Upvotes: 2

Jatmiko Herjati
Jatmiko Herjati

Reputation: 9

You should avoid state duplication, you can make FormDialog stateless component, maybe even function component. Remember to use as many stateless component as possible.

import React from 'react';

const FormDialog = props => {
  return (
    <div>
      {props.order.team}
    </div>
  );
};

export default FormDialog;

Regardless, it looks like your TypeError error appears because you

(1) Typo, it should be a

constructor (props) {
super (props);
this.state = bla bla bla ...;
  }

or just

state= bla bla bla ... 

like you did in Orders component

(2) Tried calling setstate before the component mounted. Change async componentWillMount() to componentDidMount() should works.

But don't worry about that, after you change the component to function component it shouldn't appear.

Upvotes: 0

Bruno Winck
Bruno Winck

Reputation: 11

super(props), not super( ...props) same for constructor

This link to the doc shows the proper way

https://reactjs.org/docs/react-component.html#constructor

Just after the constructor, the code is still correct but after componentWillMount state.order is replaced by this.props.order which is not initialised due to the first error.

Upvotes: 1

Related Questions