KellyCMI
KellyCMI

Reputation: 197

React Cannot read property 'id' of null

This is codesandbox I want to ask about -> https://codesandbox.io/s/2pwx46572n

When I click 'Add module' button it says 'Cannot read property 'id' of null'. I believe the problem is in thematicArea.jsx component (components -> singleModuleComponent -> thematicArea.jsx) in line 42 (key={f.id}). It says it's null after 'Add module' click, but when I console.log it in line 32 it doesn't seem to be null. So...what the problem might be? Can anybody help me to fix this?

Below thematicArea.jsx code:

import React, { Component } from "react";
import SingleModule from "./singleModule";
import { Row } from "react-bootstrap";
import _ from "lodash";

class ThematicArea extends Component {
  constructor(props) {
    super(props);
    this.takeModuleNameFromSingleModule = this.takeModuleNameFromSingleModule.bind(
      this
    );
  }
  takeModuleNameFromSingleModule(value) {
    this.props.moveModuleNameUpToApp(value);
  }

  orderedModules = _.groupBy(this.props.modules, thematicArea => {
    return thematicArea.thematicArea;
  });

  render() {
    console.log(this.orderedModules);
    console.log(this.props);
    return (
      <Row>
        <div>
          {
            (this.orderedModules = Object.keys(this.orderedModules).map(e => {
              return (
                <div key={e}>
                  <h3 key={e}>{e}</h3>
                  {/*console.log(
                    Object.values(this.orderedModules[e]).map(f => f.name + f.id)
                  )*/}
                  {Object.values(this.orderedModules[e]).map(f => (
                    <SingleModule
                      moveModuleNameUpToThematicArea={
                        this.takeModuleNameFromSingleModule
                      }
                      clickedModuleNames={this.props.clickedModuleNames}
                      chosenModulesNames={this.props.chosenModulesNames}
                      key={f.id}
                      {...f}
                    />
                  ))}
                </div>
              );
            }))
          }
        </div>
      </Row>
    );
  }
}

export default ThematicArea;

singleModule.jsx (here module is displayed)

import React, { Component } from "react";
import ShowModuleDetails from "./showModuleDetails";
import AddModule from "./addModule";
import { Col } from "react-bootstrap";

class SingleModule extends Component {
  constructor(props) {
    super(props);
    this.takeModuleNameFromAddModule = this.takeModuleNameFromAddModule.bind(
      this
    );
  }
  takeModuleNameFromAddModule(value) {
    this.props.moveModuleNameUpToThematicArea(value);
  }

  render() {
    return (
      <Col
        xs={12}
        md={6}
        lg={3}
        className={
          this.props.chosenModulesNames.includes(this.props.name) === true
            ? /*"single-module col-12 col-md-6 col-lg-3 col-xl-2*/ "single-module single-module--added"
            : /*'single-module col-12 col-md-6 col-lg-3 col-xl-2*/ "single-module single-module--not-added"
        }
      >
        <h4 className="sindgle-module__thematic-area-display">
          {this.props.thematicArea}
        </h4>
        <h3 className="single-module__module-name-display">
          {this.props.name}
        </h3>
        <div className="single-module__buttons">
          <ShowModuleDetails
            details={this.props.details}
            name={this.props.name}
          />

          <AddModule
            moveModuleNameUpToSingleModule={this.takeModuleNameFromAddModule}
            isAdded={this.isAdded}
            addNewModuleToList={this.handleAddNewModuleToList}
            name={this.props.name}
            clickedModuleNames={this.props.clickedModuleNames}
            chosenModulesNames={this.props.chosenModulesNames}
          />
        </div>
      </Col>
    );
  }
}

export default SingleModule;

And addModule.jsx (shows what happens after adding a module)

import React, { Component } from "react";
import { Button } from "react-bootstrap";

class AddModule extends Component {
  constructor(props) {
    super(props);
    this.handleAddModuleToList = this.handleAddModuleToList.bind(this);
  }

  handleAddModuleToList() {
    this.props.moveModuleNameUpToSingleModule(this.props.name);
  }

  isButtonDisabled = (chosenModulesNames, name) =>
    chosenModulesNames.includes(name);

  render() {
    const { chosenModulesNames, name } = this.props;
    return (
      <div>
        <Button
          disabled={
            this.props.chosenModulesNames.length === 122
              ? true
              : this.isButtonDisabled(chosenModulesNames, name)
          }
          bsStyle="primary"
          onClick={this.handleAddModuleToList}
          className={
            this.isButtonDisabled(chosenModulesNames, name) === true
              ? "single-module__buttons--chosen"
              : "single-module__buttons--not-chosen"
          }
        >
          {this.isButtonDisabled(chosenModulesNames, name) === true
            ? "Dodano!"
            : "Dodaj moduł"}
        </Button>
      </div>
    );
  }
}

export default AddModule;

Upvotes: 0

Views: 5438

Answers (1)

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85545

Verify this.orderedModules has data when it's being rendered like:

this.orderedModules && Object.keys(this.orderedModules).map(e => {

If everything works just fine in your current code, then you may also use:

key={f && f.id}

Upvotes: 1

Related Questions