Я создал приложение Rails 6, которое использует React в качестве внешнего интерфейса и использует Bootstrap React для моих компонентов для стайлинга. Локально все работает нормально, но когда я развертываюсь в Heroku и пытаюсь создать 'отключение', выдается следующая ошибка:
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>
открывается нормально локально. Без необходимости go разводить ключ самим модулем, есть ли более простой обходной путь или решение для этого?
Вот мой родительский компонент:
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
, а вот компонент create, содержащий сам <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