首页 > 解决方案 > 关闭模式时显示错误消息

问题描述

目标:
将 state.firstName 用于与查看模式相关的 displayModalContent。

问题:
当我打开一个模式,然后我想关闭它时,会显示一个错误“无法读取属性 'firstName' of null”。

我不知道为什么会出现这个错误,你是如何解决的?

信息:
*我是 Reactjs 的新手

Stackblitz:
https ://stackblitz.com/edit/react-qz2ywd ?

谢谢!


import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
import Modal from 'react-modal';
import Select from 'react-select';
import DisplayModalContent from './displayModalContent';

class App extends Component {
  constructor() {
    super();

    this.state = {
      openItem: null,
      items: [
        {
          firstName: 'Josef',
          lastName: 'Anderson',
          key: 'josef.anderson',
          startYear: 2021,
          startMonth: 2
        },
        {
          firstName: 'Jim',
          lastName: 'West',
          key: 'jim.west',
          startYear: 2020,
          startMonth: 3
        },
        {
          firstName: 'Joe',
          lastName: 'West',
          key: 'joe.west',
          startYear: 1998,
          startMonth: 10
        }
      ]
    };
  }

  handleOpenModal = openItem => {
    console.log(this.state);
    this.setState({ openItem });
  };

  handleCloseModal = () => {
    this.setState({ openItem: null });
  };

  handleOpenItemValue = e => {
    let { name, value } = e.target;
    this.setState({
      openItem: { ...this.state.openItem, [name]: value }
    });
  };

  handleSubmit = () => {
    console.log(document.getElementsByName('startMonth')[0].value);
    alert(
      JSON.stringify({
        test: document.getElementsByName('startMonth')[0].value
      })
    );
  };

  render() {
    const { items, openItem } = this.state;

    return (
      <div>
        <table border="1">
          <thead>
            <tr>
              <th>First Name</th>
              <th>Last Name</th>
              <th />
            </tr>
          </thead>
          <tbody>
            {items.map(item => {
              const { firstName, lastName, key } = item;

              return (
                <tr key={key}>
                  <td>{firstName}</td>
                  <td>{lastName}</td>
                  <td>
                    <button onClick={() => this.handleOpenModal(item)}>
                      Open Modal
                    </button>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
        <DisplayModalContent
          item={openItem}
          onClose={() => this.handleCloseModal()}
        />
      </div>
    );
  }
}

Modal.setAppElement(document.getElementById('root'));
render(<App />, document.getElementById('root'));

import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
import Modal from 'react-modal';
import Select from 'react-select';

const options = [
  { value: 1, label: 'Jan' },
  { value: 2, label: 'Feb' },
  { value: 3, label: 'Mars' },
  { value: 4, label: 'April' },
  { value: 5, label: 'May' },
  { value: 6, label: 'June' },
  { value: 7, label: 'July' },
  { value: 8, label: 'August' },
  { value: 9, label: 'Sept' },
  { value: 10, label: 'Oct' },
  { value: 11, label: 'Nov' },
  { value: 12, label: 'Dec' }
];

class displayModalContent extends Component {
  constructor() {
    super();

    this.state = {
      openItem: null,
      firstName: '',
      lastName: ''
    };
  }

  componentDidUpdate(s) {
    if (JSON.stringify(this.props) !== JSON.stringify(s)) {
      this.setState({ openItem: this.props.item });
      this.setState({ firstName: this.props.item.firstName });
      this.setState({ lastName: this.props.item.lastName });
    }
  }

  handleOpenModal = openItem => {
    this.setState({ openItem });
  };

  handleCloseModal = () => {
    this.setState({ openItem: null });

    this.setState({ firstName: '' });

    if (this.props.onClose) {
      this.props.onClose();
    }
  };

  handleOpenItemValue = e => {
    let { name, value } = e.target;

    this.setState({
      openItem: { ...this.state.openItem, [name]: value }
    });

    this.setState({ firstName: value });
  };

  handleOpenItemValue2 = e => {
    let { name, value } = e.target;

    this.setState({
      openItem: { ...this.state.openItem, [name]: value }
    });

    this.setState({ lastName: value });
  };

  handleSubmit = () => {
    console.log(document.getElementsByName('startMonth')[0].value);
    alert(
      JSON.stringify({
        test: document.getElementsByName('startMonth')[0].value,
        firstName: this.state.firstName,
        lastName: this.state.lastName
      })
    );
  };

  render() {
    const { items, openItem } = this.state;

    return (
      <div>
        {openItem !== null && (
          <Modal className="confirmation-modal" isOpen={true}>
            First Name:
            <br />
            <input
              type="text"
              id="firstName"
              name="firstName"
              value={openItem.firstName}
              onChange={e => this.handleOpenItemValue(e)}
            />
            <input
              type="text"
              id="lastName"
              name="lastName"
              value={openItem.lastName}
              onChange={e => this.handleOpenItemValue2(e)}
            />
            <Select
              defaultValue={options.find(
                option => option.value === openItem.startMonth
              )}
              name="startMonth"
              id="testaaa"
              options={options}
            />
            <button onClick={this.handleCloseModal}>Close Modal</button>
            <button onClick={this.handleSubmit}>Test</button>
          </Modal>
        )}
      </div>
    );
  }
}

export default displayModalContent;

h1,
p {
  font-family: Lato;
}

.confirmation-overlay.ReactModal__Overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  opacity: 0;
  background-color: rgba(0, 0, 0, 0.6);
}

.confirmation-overlay.ReactModal__Overlay--after-open {
  opacity: 1;

  transition: opacity 300ms ease-out;
}

.confirmation-modal.ReactModal__Content {
  position: absolute;

  top: 25%;
  left: 50%;
  width: 500px;
  right: auto;
  bottom: auto;
  border: 1px solid #eee;
  margin-right: -50%;
  transform: scale(0);
  background-color: #fff;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  outline: none;
  padding: 20px;
  opacity: 0;
}

.confirmation-modal.ReactModal__Content--after-open {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
  transition: all 300ms ease-out;
}

.confirmation-modal button {
  border: 1px solid black;
  background-color: #fff;
  color: #333;
  padding: 4px 8px;
  margin: 4px;
  border-radius: 3px;
  cursor: pointer;
}

.confirmation-modal button:hover {
  background-color: #eee;
}

标签: javascriptreactjs

解决方案


问题出在您尝试在 componentDidUpdate 中设置状态的 displayModalContent 文件中。当您关闭模式时,将调用 componetDidUpdate ,此时,该项目将为 null 并且您正在尝试获取 null 值的属性。因此,如果您只想在组件安装上设置一次数据,则可以使用 componentDiDMount,或者您可以使用可选链接(MDN),以便在没有来自道具的对象时不会破坏应用程序。

componentDidUpdate(s) {
    if (JSON.stringify(this.props) !== JSON.stringify(s)) {
      this.setState({ openItem: this.props.item });
      this.setState({ firstName: this.props.item?.firstName });
      this.setState({ lastName: this.props.item?.lastName });
    }
  }

推荐阅读