Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 ;=)

like image 662
Enoy Avatar asked Feb 14 '18 14:02

Enoy


2 Answers

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.

like image 191
Mayank Shukla Avatar answered Sep 29 '22 10:09

Mayank Shukla


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,
};
like image 43
Carol Chen Avatar answered Sep 29 '22 12:09

Carol Chen