0

Hello and thank you for your time!

I am currently following a React, Flux tutorial: https://app.pluralsight.com/library/courses/react-flux-building-applications/table-of-contents

The difficult I am facing is that when I try to create a new author, when I write on the form it outputs:

Uncaught TypeError: Cannot read property 'firstName' of undefined
    at ManageAuthorPage._this.setAuthorState (manageAuthorPage.js:20)
    at HTMLUnknownElement.callCallback (react-dom.development.js:542)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:581)
    at Object.invokeGuardedCallback (react-dom.development.js:438)
    at Object.invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:452)
    at executeDispatch (react-dom.development.js:836)
    at executeDispatchesInOrder (react-dom.development.js:858)
    at executeDispatchesAndRelease (react-dom.development.js:956)
    at executeDispatchesAndReleaseTopLevel (react-dom.development.js:967)
    at Array.forEach (<anonymous>)
    at forEachAccumulated (react-dom.development.js:935)
    at processEventQueue (react-dom.development.js:1112)
    at runEventQueueInBatch (react-dom.development.js:3607)
    at handleTopLevel (react-dom.development.js:3616)
    at handleTopLevelImpl (react-dom.development.js:3347)
    at batchedUpdates (react-dom.development.js:11082)
    at batchedUpdates (react-dom.development.js:2330)
    at dispatchEvent (react-dom.development.js:3421)
ManageAuthorPage._this.setAuthorState @ manageAuthorPage.js:20
callCallback @ react-dom.development.js:542
invokeGuardedCallbackDev @ react-dom.development.js:581
invokeGuardedCallback @ react-dom.development.js:438
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:452
executeDispatch @ react-dom.development.js:836
executeDispatchesInOrder @ react-dom.development.js:858
executeDispatchesAndRelease @ react-dom.development.js:956
executeDispatchesAndReleaseTopLevel @ react-dom.development.js:967
forEachAccumulated @ react-dom.development.js:935
processEventQueue @ react-dom.development.js:1112
runEventQueueInBatch @ react-dom.development.js:3607
handleTopLevel @ react-dom.development.js:3616
handleTopLevelImpl @ react-dom.development.js:3347
batchedUpdates @ react-dom.development.js:11082
batchedUpdates @ react-dom.development.js:2330
dispatchEvent @ react-dom.development.js:3421

And in the browser it details:

×
TypeError: Cannot read property 'firstName' of undefined
ManageAuthorPage._this.setAuthorState
C:/Users/YonePC/WebstormProjects/flux/src/components/authors/manageAuthorPage.js:20
  17 | setAuthorState = (event) => {
  18 |     let field = event.target.name;
  19 |     let value = event.target.value;
> 20 |     if (this.state.author.firstName !== null) {
  21 |         this.state.author[field] = value;
  22 |     } else {
  23 |         this.state = {
View compiled
▶ 16 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.

So then as you see I tried to check if this.state.author.firstName is null to create a new state to the author we are being creating, and if not, so then we are editing an existing one, and we should get the written and update it.

manageAuthorPage.js

import React from 'react';
import {AuthorForm} from "./authorForm";
import toastr from 'toastr';
import AuthorStore from "../../stores/authorStore";
import {AuthorActions} from "../../actions/myAuthorActions";

class ManageAuthorPage extends React.Component {
    state = {
        author: {
            id: '',
            firstName: '',
            lastName: '',
        },
    };

    setAuthorState = (event) => {
        let field = event.target.name;
        let value = event.target.value;
        if (this.state.author.firstName !== null) {
            this.state.author[field] = value;
        } else {
            this.state = {
                author: {
                    id: '',
                    firstName: '',
                    lastName: '',
                },
            };
        }
        return this.setState({author: this.state.author});
    };

    saveAuthor = (event) => {
        event.preventDefault();
        AuthorActions.createAuthor(this.state.author);
        toastr.success('Author saved ;=)');
    };

    componentDidMount = () => {
        const queryAuthorId = this.props.location.pathname; //from the path '/author:id'
        const authorId = queryAuthorId.substr(queryAuthorId.lastIndexOf("/") + 1);

        if (authorId) {
            this.setState({author: AuthorStore.getAuthorById(authorId)});
        }
        // console.log(authorId.substr(authorId.lastIndexOf("/") + 1));

    };

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

export {ManageAuthorPage}

And also I include the children component because they could be important for this issue:

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

class AuthorForm extends React.Component {


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

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

                <Input
                    name="lastName"
                    label="Last Name"
                    value={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 I think the deeper child is not related to this difficulty, but for clarity I include it:

import React from 'react';
import PropTypes from 'prop-types';

class Input extends React.Component {


    render() {
        let wrapperClass = 'form-group';
        if (this.props.error && this.props.error.length > 0) {
            wrapperClass += ' ' + 'has-error';
        }
        return (
            <div className={wrapperClass}>
                <label htmlFor={this.props.name}>{this.props.label}</label>
                <div className="field">
                    <input type="text"
                           name={this.props.name}
                           className="form-control"
                           placeholder={this.props.placeholder}
                           ref={this.props.name}
                           value={this.props.value}
                           onChange={this.props.onChange}
                    />
                    <div className="input">{this.props.error}</div>
                </div>
            </div>
        );
    }
}


export {Input};

In addition we have here the full app which I have writen following the tutorial: https://github.com/YoneMoreno/ReactFluxAuthorsPageTutorial

I have also read for information:

https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/undefined

How to check for "undefined" in JavaScript?

How to determine if variable is 'undefined' or 'null'?

Could you help me???

Thank you for your time.

Yone
  • 2,064
  • 5
  • 25
  • 56
  • 1
    i see a check to `this.state.author.firstName`, but not to `this.state.author`. – cosh Feb 14 '18 at 16:01
  • yea I think you should check for `this.state.author` – Tim Han Feb 14 '18 at 16:10
  • I'm fairly new to react but on top of what the others said... I think you might want to include a constructor to wrap your state in. In your case: `constructor(props){ super(props); this.state = { author: { id: '', firstName: '', lastName: '' } }; ` purely for management of 'this' later in your program. – Jeff L Feb 14 '18 at 16:33
  • that's kind of the next thing that I'm skeptical about. The context binding for `this` – Tim Han Feb 14 '18 at 16:41

1 Answers1

2

Be aware that :

null === undefined // false! 

Lets say ..

let a = undefined 
a === undefined // true 

But ..

a === null // false
a == null // true

So something like this may help you here :

 if (this.state.author.firstName !== undefined) { 
        this.state.author[field] = value;
    } 

Or check for both null and undefined

 if (this.state.author.firstName != null) {  
            this.state.author[field] = value;
        } 
toufek khoury
  • 2,974
  • 2
  • 8
  • 15