Yone
Yone

Reputation: 2134

React: How to check if received props are undefined?

Hello and thank you for your time:

I am following the following tutorial:https://app.pluralsight.com/library/courses/react-flux-building-applications/table-of-contents

And currently I have detected that when you try to create an author, it tries to load current's author's URL's author id. Because of it is being created, it is undefined, and so then the create author functionality does not work.

I have read some topics about checking undefined type both in JS and React: How to determine if variable is 'undefined' or 'null'?

Checking for Undefined In React

https://github.com/facebook/react/issues/3725

And I have tried the following:

In manageAuthorForm we pass in to the authorForm the author's state:

  render() {
        return (
            <AuthorForm author={this.state.author}
                        onChange={this.setAuthorState}
                        onSave={this.saveAuthor}/>
        );
    };

And then I have tried into the AuthorForm:

import React from 'react';
import {Input} from "../common/textInput";
import Link from "react-router-dom/es/Link";

class AuthorForm extends React.Component {
    componentWillReceiveProps(nextProps) {
        if (nextProps.state.author === undefined) {
            this.props.author = {
                author: {
                    id: '',
                    firstName: '',
                    lastName: '',

                }
            };
        }
    }

    render() {
        return (
            <form>
                <h1>Manage author</h1>
                <Input
                    name="firstName"
                    label="First Name"
                    value={this.props.author.firstName}
                    onChange={this.props.onChange}
                />

                <Input
                    name="lastName"
                    label="Last Name"
                    value={this.props.author.lastName}
                    onChange={this.props.onChange}
                />

                <button type="submit" value="Save" className="btn btn-default" onClick={this.props.onSave}><Link
                    to="/authors">Save
                    author</Link>
                </button>
            </form>
        );
    }
}

export {AuthorForm}

And it reports that nextProps are undefined:

Uncaught TypeError: Cannot read property 'author' of undefined
    at AuthorForm.componentWillReceiveProps (authorForm.js:7)
    at callComponentWillReceiveProps (react-dom.development.js:6389)
    at updateClassInstance (react-dom.development.js:6575)
    at updateClassComponent (react-dom.development.js:7848)
    at beginWork (react-dom.development.js:8225)
    at performUnitOfWork (react-dom.development.js:10224)
    at workLoop (react-dom.development.js:10288)
    at HTMLUnknownElement.callCallback (react-dom.development.js:542)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:581)
    at invokeGuardedCallback (react-dom.development.js:438)
    at renderRoot (react-dom.development.js:10366)
    at performWorkOnRoot (react-dom.development.js:11014)
    at performWork (react-dom.development.js:10967)
    at requestWork (react-dom.development.js:10878)
    at scheduleWorkImpl (react-dom.development.js:10732)
    at scheduleWork (react-dom.development.js:10689)
    at scheduleTopLevelUpdate (react-dom.development.js:11193)
    at Object.updateContainer (react-dom.development.js:11231)
    at react-dom.development.js:15226
    at Object.unbatchedUpdates (react-dom.development.js:11102)
    at renderSubtreeIntoContainer (react-dom.development.js:15225)
    at Object.render (react-dom.development.js:15290)
    at Object../src/index.js (index.js:17)
    at __webpack_require__ (bootstrap 78b34f0f34b98a41c613:678)
    at fn (bootstrap 78b34f0f34b98a41c613:88)
    at Object.0 (authorStore.js:39)
    at __webpack_require__ (bootstrap 78b34f0f34b98a41c613:678)
    at bootstrap 78b34f0f34b98a41c613:724
    at bootstrap 78b34f0f34b98a41c613:724
componentWillReceiveProps @ authorForm.js:7
callComponentWillReceiveProps @ react-dom.development.js:6389
updateClassInstance @ react-dom.development.js:6575
updateClassComponent @ react-dom.development.js:7848
beginWork @ react-dom.development.js:8225
performUnitOfWork @ react-dom.development.js:10224
workLoop @ react-dom.development.js:10288
callCallback @ react-dom.development.js:542
invokeGuardedCallbackDev @ react-dom.development.js:581
invokeGuardedCallback @ react-dom.development.js:438
renderRoot @ react-dom.development.js:10366
performWorkOnRoot @ react-dom.development.js:11014
performWork @ react-dom.development.js:10967
requestWork @ react-dom.development.js:10878
scheduleWorkImpl @ react-dom.development.js:10732
scheduleWork @ react-dom.development.js:10689
scheduleTopLevelUpdate @ react-dom.development.js:11193
updateContainer @ react-dom.development.js:11231
(anonymous) @ react-dom.development.js:15226
unbatchedUpdates @ react-dom.development.js:11102
renderSubtreeIntoContainer @ react-dom.development.js:15225
render @ react-dom.development.js:15290
./src/index.js @ index.js:17
__webpack_require__ @ bootstrap 78b34f0f34b98a41c613:678
fn @ bootstrap 78b34f0f34b98a41c613:88
0 @ authorStore.js:39
__webpack_require__ @ bootstrap 78b34f0f34b98a41c613:678
(anonymous) @ bootstrap 78b34f0f34b98a41c613:724
(anonymous) @ bootstrap 78b34f0f34b98a41c613:724

And in the web browser it reports:

×
TypeError: Cannot read property 'author' of undefined
AuthorForm.componentWillReceiveProps
C:/Users/YonePC/WebstormProjects/flux/src/components/authors/authorForm.js:7
   4 | 
   5 | class AuthorForm extends React.Component {
   6 |     componentWillReceiveProps(nextProps) {
>  7 |         if (nextProps.state.author === undefined) {
   8 |             this.props.author = {
   9 |                 author: {
  10 |                     id: '',
View compiled
▶ 15 stack frames were collapsed.
This screen is visible only in development. It will not appear if the app crashes in production.
Open your browser’s developer console to further inspect this error.

The full code, in github: https://github.com/YoneMoreno/ReactFluxAuthorsPageTutorial

Could you help me, please?

Thank you ;=)

Upvotes: 11

Views: 48282

Answers (5)

Yanov
Yanov

Reputation: 674

const UndefinedCheck =  data => {
    if(data === undefined){
        return 1
    }else {
        return data
    }
}

export default UndefinedCheck

Upvotes: 0

Yoan
Yoan

Reputation: 2197

nextProps.state ?

The one that has a state it is the component, Please decide where are you going to handle the author data. In the component props or in the state.

Besides that you should take a look of: https://www.npmjs.com/package/prop-types

Its a library for react to handle types and default values for your component props. With this library you are going to be able to do somethings like:

FunctionPointAutomatedTable.defaultProps = {
  dataSource: [],
};

FunctionPointAutomatedTable.propTypes = {
  applicationId: PropTypes.string,
  functionType: PropTypes.string,
  dataSource: PropTypes.array,
  allowedTypes: PropTypes.array,
  onEdit: PropTypes.func,
  onDelete: PropTypes.func,
  onIgnore: PropTypes.func,
  onMerge: PropTypes.func,
  onUnmerge: PropTypes.func,
};

Upvotes: 0

Carol Chen
Carol Chen

Reputation: 997

Your error message is; Cannot read property 'author' of undefined

It is actually not author that is undefined but nextProps.state. nextProps is an object containing the contents of only the props.

The other problem here is that componentWillReceiveProps() is not called when when mounting, thus if props.author is initially undefined then that error handling won't work. Mayank Shukla has a good answer, however that requires you to have a constructor like so;

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

Since props cannot be updated, it makes more sense to put it in the state so that it can be in the future. If you need to receive prop updates, use setState() in componentWillUpdate()

Another, more long winded solution would be to make author a required prop, and not attempt to create that component until the necessary props exist. This is also better practice.

AuthorForm.propTypes = {
  author: PropTypes.string.isRequired,
};

Upvotes: 2

Mayank Shukla
Mayank Shukla

Reputation: 104399

Simple solution will be:

<AuthorForm 
   author={this.state.author || {firstName:'', lastName:'', id:''}}
   ...
/>

And remove the componentWillReceiveProps method from child component.

Better approach will be:

1- Either assign the initial value of author in state as:

this.state = {
   author: {firstName:'', lastName:'', id:''}
}

2- Or inside render method of child component, write it like this:

render(){

   const {firstName='', lastName='', id=''} = this.props.author || {};

   return(....)
}

And use firstName, lastName, id directly instead of this.props.


Issues in your code:

1- It should be nextProps.author instead of nextProps.state.author in componentWillReceiveProps lifecycle method.

2- Props are read-only, Whether you declare a component as a function or a class, it must never modify its own props. You are trying to change the value in componentWillReceiveProps.

Upvotes: 7

stadnik0ff
stadnik0ff

Reputation: 1700

You should setUp default values to {this.state.author} which you set to component instead of setting default values to props into

Upvotes: 0

Related Questions