Bootstrap Modal causes 'Uncaught TypeError: Cannot convert undefined or null to object' error in Heroku with Rails 6 app

Bootstrap Modal causes 'Uncaught TypeError: Cannot convert undefined or null to object' error in Heroku with Rails 6 app

我构建了一个 Rails 6 应用程序,它使用 React 作为前端,并使用 Bootstrap React 作为我的样式组件。在本地一切正常,但是当我部署到 Heroku 并尝试创建一个 'outage' 时,它会抛出以下错误:

Modal.js:21 Uncaught TypeError: Cannot convert undefined or null to object
    at hasOwnProperty (<anonymous>)
    at Modal.js:21
    at Array.forEach (<anonymous>)
    at Modal.js:20
    at t.n.render (Modal.js:302)
    at Qi (react-dom.production.min.js:4243)
    at Ji (react-dom.production.min.js:4234)
    at wc (react-dom.production.min.js:6676)
    at yu (react-dom.production.min.js:5650)
    at Mu (react-dom.production.min.js:5639)

同样,<Modal> 在本地打开良好。不必去猴子扳手模块本身,是否有更简单的解决方法或解决方案?

这是我的父组件:

import React, { Component } from "react";
import RecurringOutageComponent from "./components/RecurringOutageComponent";
import FutureOutageComponent from "./components/FutureOutageComponent";
import CurrentOutagesComponent from "./components/CurrentOutagesComponent";
import CreateModalComponent from "./components/CreateModalComponent";
import { Container, Row, Col, Image } from "react-bootstrap";
import { getFutureOutages } from "./actions/fetchFutureOutagesAction";
import { getRecurringOutages } from "./actions/fetchRecurringOutagesAction";
import { getServices } from "./actions/fetchServicesAction";
import { getCurrentOutages } from "./actions/fetchCurrentOutagesAction";
import { connect } from 'react-redux'; 


class Dashboard extends Component {
  state = {
    showModal: false
  };

  componentDidMount() {
    this.props.getFutureOutages()
    this.props.getRecurringOutages()
    this.props.getServices()
    this.props.getCurrentOutages()
  }

render() {
    console.log(this.props)
    return (
      <div>
        <Container>
          <Row>
            <Col lg={1}>
              <img
                src={require("./public/logo-2-dashboard.png")}
                alt="logo"
                id="logo"
              ></img>
            </Col>
            <Col md={10}></Col>
          </Row>
        </Container>
        <Container>
          <div className="d-flex justify-content-md-end bd-highlight">
            <CreateModalComponent
              show={this.state.showModal}
              services={this.props.services}
            />
          </div>
        </Container>
        <div className="d-flex justify-content-center bd-highlight dashboard">
          <div className="d-flex justify-content-start bd-highlight">
            <div className="d-fliex pastOutages">
              <h4>Past Outages</h4>
            </div>
          </div>
          <div className="d-flex justify-content-center bd-highlight">
            <div className="d-fliex currentOutages">
              <h4>Current Outages</h4>
              <div className="container">
                <div className="col-12">
                  <CurrentOutagesComponent />
                </div>
              </div>
            </div>
          </div>
          <div className="d-flex align-items-center flex-column bd-highlight">
            <div className="d-fliex justify-content-center">
              <h4>Future Outages</h4>
              <div className="container" id="futureOutages">
                <div className="col-12">
                  <FutureOutageComponent 
                  />
                </div>
              </div>

              <h4>Recurring Outages</h4>
              <Container id="recurringOutages">
                <div className="col-12">
                  <RecurringOutageComponent
                    />
                </div>
              </Container>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    outages: state.outages, 
    futureOutages: state.futureOutages.futureOutages,
    recurringOutages: state.recurringOutages.recurringOutages,
    services: state.services.services,
    currentOutages: state.currentOutages.currentOutages
  }
};


const mapDispatchToProps = dispatch => {
  return {
    getOutages: () => dispatch(getOutages()),
    getFutureOutages: () => dispatch(getFutureOutages()),
    getRecurringOutages: () => dispatch(getRecurringOutages()),
    getServices: () => dispatch(getServices()),
    getCurrentOutages: () => dispatch(getCurrentOutages())
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Dashboard); // this connects Dashboard to store

这是包含 <Modal> 本身的创建组件:

import React, { Component } from "react";
import {
  Modal,
  Button,
  Form,
  InputGroup,
  DropdownButton,
  Dropdown,
  FormControl
} from "react-bootstrap";
import DateTimePicker from "react-datetime-picker";
import { createFutureOutage } from "../actions/createFutureOutageAction";
import { createRecurringOutage } from "../actions/createRecurringOutageAction";
import { connect } from "react-redux";
const uuidv4 = require("uuid/v4"); 
import Moment from "react-moment";
import "moment-timezone";

class CreateModalComponent extends Component {
  state = {
    showModal: false,
    startTime: new Date(),
    endTime: new Date(),
    service: "",
    outageType: "",
    frequency: "",
    reason: ""
  };

  handleClose = () => this.setState({ showModal: false });

  handleShow = () => this.setState({ showModal: true });

  onChangeStart = date => {
    this.setState({ startTime: date });
  };

  onChangeEnd = date => {
    this.setState({ endTime: date });
  };

  handleChange = (name, value) => this.setState({ [name]: value });

  handleReason = e => {
    this.setState({ reason: e.currentTarget.value });
  };

  showFrequency = () => {
    this.state.frequency === 0 ? "Frequency" : this.state.frequency;
  };

  handleSubmit = e => {
    e.preventDefault();
        const {
          startTime,
          endTime,
          frequency,
          outageType,
          reason,
          service,
          outageId
        } = this.state;

    if (this.state.outageType === "FO") { 
      this.props.createFutureOutage(
        startTime,
        endTime,
        frequency,
        outageType,
        reason,
        service.id,
        outageId
      ); 
    }
    else if (this.state.outageType === "RO") {
      this.props.createRecurringOutage(
        startTime,
        endTime,
        frequency,
        outageType,
        reason,
        service.id,
        outageId
      );
    }
    this.handleClose();
  };



  render() {

    const frequency = ["Hourly", "Daily", "Weekly", "Monthly", "None"];
    const outageType = ["FO", "RO"];
    return (
      <>
        <Button variant="outline-primary" onClick={this.handleShow}>
          Create Outage
        </Button>

        <Modal
          show={this.state.showModal}
          onHide={this.handleClose}
          animation={false}
        >
          <Modal.Header closeButton>
            <Modal.Title>Create Outage</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <Form onSubmit={e => this.handleSubmit(e)}>
              <Form.Group>
                Start Date
                <DateTimePicker
                  onChange={this.onChangeStart}
                  value={this.state.startTime}
                  returnValue="start"
                />
              </Form.Group>
              <Form.Group>
                End Date
                <DateTimePicker
                  onChange={this.onChangeEnd}
                  value={this.state.endTime}
                  returnValue="end"
                />
                <DropdownButton
                  as={InputGroup.Prepend}
                  variant="outline-secondary"
                  title={
                    this.state.service.length === 0
                      ? "Service"
                      : this.state.service.service
                  }
                  id="input-group-dropdown-1"
                >
                  {this.props.services.map(service => {
                    return (
                      <Dropdown.Item
                        key={uuidv4()}
                        onSelect={() => this.handleChange("service", service)}
                      >
                        {service.service}
                      </Dropdown.Item>
                    );
                  })}
                </DropdownButton>
                <DropdownButton
                  as={InputGroup.Prepend}
                  variant="outline-secondary"
                  title={
                    this.state.outageType.length === 0
                      ? "Outage Type"
                      : this.state.outageType
                  }
                  id="input-group-dropdown-1"
                >
                  {outageType.map((outage) => {
                    return (
                      <Dropdown.Item
                        key={uuidv4()}
                        onSelect={() => this.handleChange("outageType", outage)}
                      >
                        {outage}
                      </Dropdown.Item>
                    );
                  })}
                </DropdownButton>
                {this.state.outageType === "RO" ? (
                  <DropdownButton
                    as={InputGroup.Prepend}
                    variant="outline-secondary"
                    title={
                      this.state.frequency === ""
                        ? "Frequency"
                        : this.state.frequency
                    }
                    id="input-group-dropdown-1"
                  >
                    {frequency.map((freq, idx) => {
                      return (
                        <Dropdown.Item
                          key={idx}
                          onSelect={() => this.handleChange("frequency", freq)}
                        >
                          {freq}
                        </Dropdown.Item>
                      );
                    })}
                  </DropdownButton>
                ) : null}
                <Form.Group controlId="exampleForm.ControlTextarea1">
                  <Form.Label>Reason</Form.Label>
                  <Form.Control
                    as="textarea"
                    onChange={e => this.handleReason(e)}
                    rows="3"
                  />
                </Form.Group>
              </Form.Group>
              <Button variant="primary" type="submit">
                Submit
              </Button>
            </Form>
          </Modal.Body>
        </Modal>
      </>
    );
  }
}

const mapDispatchToProps = dispatch => {
  return {
    createFutureOutage: (startTime, endTime, frequency, outageType, reason, serviceId) =>
      dispatch(createFutureOutage(
              startTime,
              endTime,
              frequency,
              outageType,
              reason,
              serviceId
      )
            ),
    createRecurringOutage: (startTime, endTime, frequency, outageType, reason, serviceId) => 
          dispatch(createRecurringOutage(
              startTime,
              endTime,
              frequency,
              outageType,
              reason,
              serviceId
            )
      )
  };
};

export default connect(null, mapDispatchToProps)(CreateModalComponent);

我的 NPM 包安装深度为 1

Users/demiansims/.nvm/versions/node/v8.16.0/lib
├─┬ npm@6.4.1
│ ├── abbrev@1.1.1
│ ├── ansicolors@0.3.2
│ ├── ansistyles@0.1.3
│ ├── aproba@1.2.0
│ ├── archy@1.0.0
│ ├── bin-links@1.1.2
│ ├── bluebird@3.5.1
│ ├── byte-size@4.0.3
│ ├── cacache@11.2.0
│ ├── call-limit@1.1.0
│ ├── chownr@1.0.1
│ ├── ci-info@1.4.0
│ ├── cli-columns@3.1.2
│ ├── cli-table3@0.5.0
│ ├── cmd-shim@2.0.2
│ ├── columnify@1.5.4
│ ├── config-chain@1.1.11
│ ├── debuglog@1.0.1
│ ├── detect-indent@5.0.0
│ ├── detect-newline@2.1.0
│ ├── dezalgo@1.0.3
│ ├── editor@1.0.0
│ ├── figgy-pudding@3.4.1
│ ├── find-npm-prefix@1.0.2
│ ├── fs-vacuum@1.2.10
│ ├── fs-write-stream-atomic@1.0.10
│ ├── gentle-fs@2.0.1
│ ├── glob@7.1.2
│ ├── graceful-fs@4.1.11
│ ├── has-unicode@2.0.1
│ ├── hosted-git-info@2.7.1
│ ├── iferr@1.0.2
│ ├── imurmurhash@0.1.4
│ ├── inflight@1.0.6
│ ├── inherits@2.0.3
│ ├── ini@1.3.5
│ ├── init-package-json@1.10.3
│ ├── is-cidr@2.0.6
│ ├── json-parse-better-errors@1.0.2
│ ├── JSONStream@1.3.4
│ ├── lazy-property@1.0.0
│ ├── libcipm@2.0.2
│ ├── libnpmhook@4.0.1
│ ├── libnpx@10.2.0
│ ├── lock-verify@2.0.2
│ ├── lockfile@1.0.4
│ ├── lodash._baseindexof@3.1.0
│ ├── lodash._baseuniq@4.6.0
│ ├── lodash._bindcallback@3.0.1
│ ├── lodash._cacheindexof@3.0.2
│ ├── lodash._createcache@3.1.2
│ ├── lodash._getnative@3.9.1
│ ├── lodash.clonedeep@4.5.0
│ ├── lodash.restparam@3.6.1
│ ├── lodash.union@4.6.0
│ ├── lodash.uniq@4.5.0
│ ├── lodash.without@4.4.0
│ ├── lru-cache@4.1.3
│ ├── meant@1.0.1
│ ├── mississippi@3.0.0
│ ├── mkdirp@0.5.1
│ ├── move-concurrently@1.0.1
│ ├── node-gyp@3.8.0
│ ├── nopt@4.0.1
│ ├── normalize-package-data@2.4.0
│ ├── npm-audit-report@1.3.1
│ ├── npm-cache-filename@1.0.2
│ ├── npm-install-checks@3.0.0
│ ├── npm-lifecycle@2.1.0
│ ├── npm-package-arg@6.1.0
│ ├── npm-packlist@1.1.11
│ ├── npm-pick-manifest@2.1.0
│ ├── npm-profile@3.0.2
│ ├── npm-registry-client@8.6.0
│ ├── npm-registry-fetch@1.1.0
│ ├── npm-user-validate@1.0.0
│ ├── npmlog@4.1.2
│ ├── once@1.4.0
│ ├── opener@1.5.0
│ ├── osenv@0.1.5
│ ├── pacote@8.1.6
│ ├── path-is-inside@1.0.2
│ ├── promise-inflight@1.0.1
│ ├── qrcode-terminal@0.12.0
│ ├── query-string@6.1.0
│ ├── qw@1.0.1
│ ├── read@1.0.7
│ ├── read-cmd-shim@1.0.1
│ ├── read-installed@4.0.3
│ ├── read-package-json@2.0.13
│ ├── read-package-tree@5.2.1
│ ├── readable-stream@2.3.6
│ ├── readdir-scoped-modules@1.0.2
│ ├── request@2.88.0
│ ├── retry@0.12.0
│ ├── rimraf@2.6.2
│ ├── safe-buffer@5.1.2
│ ├── semver@5.5.0
│ ├── sha@2.0.1
│ ├── slide@1.1.6
│ ├── sorted-object@2.0.1
│ ├── sorted-union-stream@2.1.3
│ ├── ssri@6.0.0
│ ├── stringify-package@1.0.0
│ ├── tar@4.4.6
│ ├── text-table@0.2.0
│ ├── tiny-relative-date@1.3.0
│ ├── uid-number@0.0.6
│ ├── umask@1.1.0
│ ├── unique-filename@1.1.0
│ ├── unpipe@1.0.0
│ ├── update-notifier@2.5.0
│ ├── uuid@3.3.2
│ ├── validate-npm-package-license@3.0.4
│ ├── validate-npm-package-name@3.0.0
│ ├── which@1.3.1
│ ├── worker-farm@1.6.0
│ └── write-file-atomic@2.3.0
└─┬ tml_dashboard@0.1.0 -> /Users/demiansims/Development/tml_info/tml_dashboard
  ├── @babel/preset-react@7.8.3
  ├── @rails/actioncable@6.0.2
  ├── @rails/activestorage@6.0.2
  ├── @rails/ujs@6.0.2
  ├── @rails/webpacker@4.2.2
  ├── axios@0.19.2
  ├── babel-plugin-transform-react-remove-prop-types@0.4.24
  ├── bootstrap@4.4.1
  ├── dotenv@8.2.0
  ├── jquery@3.4.1
  ├── moment@2.24.0
  ├── moment-timezone@0.5.27
  ├── node-pre-gyp@0.14.0
  ├── popper.js@1.16.1
  ├── prop-types@15.7.2
  ├── qs@6.9.1
  ├── react@16.12.0
  ├── react-bootstrap@1.0.0-beta.16
  ├── react-datetime-picker@2.9.0
  ├── react-dom@16.12.0
  ├── react-input-range@1.3.0
  ├── react-moment@0.9.7
  ├── react-redux@7.1.3
  ├── react-simple-timefield@3.0.0
  ├── react-time-picker@3.9.0
  ├── redux@4.0.5
  ├── redux-thunk@2.3.0
  ├── turbolinks@5.2.0
  ├── uuid@3.4.0
  └── webpack-dev-server@3.10.3

假设 propTypes 是在产品中定义的,那么 ReactBootstrap 似乎有问题。

您可以更新 Rails babel.config.js 文件以忽略 babel-plugin-transform-react-remove-prop-types 这实际上是导致错误的原因。

例如,您可以将这些行注释掉,并留下注释说明它为什么被注释掉。例如

// babel.config.js

// Remove babel-plugin-transform-react-remove-prop-types to get
// Bootstrap-React@1.0.0-beta.16 working properly
// isProductionEnv && [
//   'babel-plugin-transform-react-remove-prop-types',
//   {
//     removeImport: true
//   }
// ]

请参见 BootstrapReact 的 Github 存储库中的 issue