Negant
Negant

Reputation: 119

Cannot read property 'props' of undefined in react, pass data from parent to child

I'm sitting with this for a while and wondering if there is any possibility of passing the state from parent to child in this case?

I need this id to give input and label an unique id couse this component is used multiple times.

Thanks for any advice.

Parent:

<FileUpload key={el.id} parentCallback={this.callback(el.id)} id={el.id}/>

Child:

import React, { Fragment, useState } from 'react';
import Message from './Message';
import Progress from './Progress';
import axios from 'axios';

const FileUpload = ({ parentCallback }) => {

  return (
    <Fragment>
      <form className="image__uploadForm" onSubmit={onSubmit}>

        {this.props.id} // Causes error props undef

        <div className='image__upload'>
          <input
            type='file'
            className='input__uploadFile'
            id='uploadFile'
            accept="image/*"
            onChange={onChange}
          />
          <label className='input__uploadFile--label' htmlFor='uploadFile'>
            {filename}
          </label>
          {!file ? (
            null
          ) :
          <input
            type='submit'
            value='Upload'
          />
        }
        </div>
      </form>
    </Fragment>
  );
};

export default FileUpload;

Upvotes: 0

Views: 602

Answers (2)

Antoni
Antoni

Reputation: 1433

You can not pass your callback like this parentCallback={this.callback(el.id)} because it will be executed instantly by render. You could try to pass in an error function like parentCallback={() => this.callback(el.id)} and call it in the submit function

Id is undefined because Id is a key word and will be not passed

Parent:

<FileUpload key={el.id} parentCallback={() => this.callback(el.id)} {...el}/>

Child:

import React, { Fragment, useState } from 'react';
import Message from './Message';
import Progress from './Progress';
import axios from 'axios';

const FileUpload = ({ parentCallback, id }) => {
  const onSubmit = () => {
    return parentCallback()
  }

  return (
    <Fragment>
      <form className="image__uploadForm" onSubmit={onSubmit}>

        {id}

        <div className='image__upload'>
          <input
            type='file'
            className='input__uploadFile'
            id='uploadFile'
            accept="image/*"
            onChange={onChange}
          />
          <label className='input__uploadFile--label' htmlFor='uploadFile'>
            {filename}
          </label>
          {file && <input type='submit' value='Upload'/>} //Tip: If you work with && you do not need to return null
        </div>
      </form>
    </Fragment>
  );
};

export default FileUpload;

Otherwise you can pass your function like:

Parent: <FileUpload key={el.id} parentCallback={this.callback} {...el}/> Child:

....
const FileUpload = ({ parentCallback, id }) => {
  const onSubmit = () => {
    return parentCallback(id)
  }

  return (....)
}

Upvotes: 0

Brian Thompson
Brian Thompson

Reputation: 14365

As @ajobi said, this will not be defined in a functional component using the arrow syntax.

You can solve this three ways:

1. Use the rest syntax to gather all props except parentCallback into a variable called props:

const FileUpload = ({ parentCallback, ...props }) => {
...
{props.id}

2. Spread all props into their own variables:

const FileUpload = ({ parentCallback, id }) => {
...
{id}

3. Spread none of the variables and use the props object when using all props in your component:

const FileUpload = (props) => {
...
{props.id}
...
props.parentCallback

Upvotes: 2

Related Questions