I’m trying to retrieve a list of prisons which has a nested object address. It is structured like this:
{ uuid,
address: {
city,
country,
state,
street,
zip },
prisonName,
rules,
}
For the sake of simplicity all other objects are strings for now.
I’m getting the error “Error: Objects are not valid as a React child (found: object with keys {city, zip, state, country, street}). If you meant to render a collection of children, use an array instead.” but I’ve poured over my code a dozen times, I know I can’t render Address, it’s an object, not a string, but I don’t render it. I render properties of it, but never the whole object.
I even commented out any instances where I was console.logging the address just to be on the safe side.
prisons.js
import * as ActionTypes from './types'
import PrisonDataService from '../services/prison.service'
export const createPrison = (prisonName, address, rules) => async (dispatch) => {
try {
const res = await PrisonDataService.create({ prisonName, address, rules })
dispatch({
type: ActionTypes.CREATE_PRISON,
payload: res.data,
});
return Promise.resolve(res.data);
} catch (err) {
return Promise.reject(err)
}
};
export const retrievePrisons = () => async (dispatch) => {
try {
const res = await PrisonDataService.getAll();
dispatch({ //This is where the compiler says the error is
type: ActionTypes.RETRIEVE_PRISONS,
payload: res.data,
});
} catch (err) {
console.log(err)
}
};
export const updatePrison = (id, data) => async (dispatch) => {
try {
const res = await PrisonDataService.update(id, data);
dispatch({
type: ActionTypes.UPDATE_PRISON,
payload: data,
});
return Promise.resolve(res.data);
} catch (err) {
return Promise.reject(err);
}
};
export const deletePrison = (id) => async (dispatch) => {
try {
await PrisonDataService.delete(id);
dispatch({
type: ActionTypes.DELETE_PRISON,
payload: { id },
});
} catch (err) {
console.log(err);
}
};
export const deleteAllPrisons = () => async (dispatch) => {
try {
const res = await PrisonDataService.deleteAll();
dispatch({
type: ActionTypes.DELETE_ALL_PRISONS,
payload: res.data,
});
return Promise.resolve(res.data);
} catch (err) {
return Promise.reject(err);
}
};
export const findPrisonByName = (name) => async (dispatch) => {
try {
const res = await PrisonDataService.findByName(name);
dispatch({
type: ActionTypes.RETRIEVE_PRISONS,
payload: res.data,
});
} catch (err) {
console.log(err);
}
};
prison-list.component.js
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { Button, Col, Input, InputGroup, Label, List, ListGroup } from "reactstrap";
import { retrievePrisons, findPrisonByName, deleteAllPrisons } from "../../actions/prisons";
import AddPrison from "./add-prison.component"
class PrisonsList extends Component {
constructor(props) {
super(props);
this.onChangeSearchName = this.onChangeSearchName.bind(this);
this.refreshData = this.refreshData.bind(this);
this.setActivePrison = this.setActivePrison.bind(this);
this.findByName = this.findByName.bind(this);
this.removeAllPrisons = this.removeAllPrisons.bind(this);
this.state = {
currentPrison: null,
currentIndex: -1,
searchName: " ",
};
}
componentDidMount() {
this.props.retrievePrisons();
}
onChangeSearchName(e) {
const searchName = e.target.value;
this.setState({
searchName: searchName,
});
}
refreshData() {
this.setState({
currentPrison: null,
currentIndex: -1,
});
}
setActivePrison(prison, index) {
console.log(prison)
this.setState({
currentPrison: prison,
currentIndex: index,
});
}
removeAllPrisons() {
this.props
.deleteAllPrisons()
.then((response) => {
console.log(response);
this.refreshData();
})
.catch((e) => {
console.log(e);
});
}
findByName() {
this.refreshData();
this.props.findPrisonByName(this.state.searchName);
}
render() {
const { searchName, currentPrison, currentIndex } = this.state;
const { prisons } = this.props;
console.log(prisons)
return (
<List className="row">
<Col md="8">
<InputGroup className="mb-3">
<Input
type="text"
className="form-control"
placeholder="Search by name"
value={searchName}
onChange={this.onChangeSearchName}
/>
<div className="input-group-append">
<Button
outline
color="secondary"
onClick={this.findByName}
>
Search
</Button>
</div>
</InputGroup>
</Col>
<div className="col-md-6">
<h4>Prison List</h4>
<ListGroup>
{prisons &&
prisons.map((prison, index) => (
<li
className={
"list-group-item " +
(index === currentIndex ? "active" : "")
}
onClick={() => this.setActivePrison(prison, index)}
key={index}
>
{prison.prisonName}
</li>
))}
</ListGroup>
<Button
color="danger"
className="m-3"
onClick={this.removeAllPrisons}
>
Remove All
</Button>
</div>
<Col md={6}>
{currentPrison ? (
<div>
<h4>Prison</h4>
<div>
<Label>
<strong>Prison Name:</strong>
</Label>{" "}
{currentPrison.prisonName}
</div>
<div>
<Label>
<strong>Address:</strong>
</Label>{" "}
{currentPrison.address.street}
</div>
{/* {console.log(currentPrison.address)} */}
<div>
<Label>
<strong>UUID:</strong>
</Label>{" "}
{currentPrison.uuid}
</div>
<div>
<Label>
<strong>Inmates:</strong>
</Label>{" "}
{currentPrison.inmates}
</div>
<Link
to={"/prison/" + currentPrison.uuid}
>
Edit
</Link>
</div>
) : (
<div>
<br />
<p>Please click on a Prison...</p>
</div>
)}
</Col>
<h1>Add Prison</h1>
<AddPrison/>
</List> );
}
}
const mapStateToProps = (state) => {
return {
prisons: state.prisons,
};
};
export default connect(mapStateToProps, { retrievePrisons, findPrisonByName, deleteAllPrisons })(PrisonsList);
prison.component.js
import React, { Component } from "react";
import { connect } from "react-redux";
import { updatePrison, deletePrison } from "../../actions/prisons";
import PrisonDataService from "../../services/prison.service";
import { Button, Form, FormGroup, Input, Label } from "reactstrap"
class Prison extends Component {
constructor(props) {
super(props);
this.onChangePrisonName = this.onChangePrisonName.bind(this);
this.onChangeCity = this.onChangeCity.bind(this);
this.onChangeCountry = this.onChangeCountry.bind(this);
this.onChangeState = this.onChangeState.bind(this);
this.onChangeStreet = this.onChangeStreet.bind(this);
this.onChangeZip = this.onChangeZip.bind(this);
this.onChangeRules = this.onChangeRules.bind(this);
this.getPrison = this.getPrison.bind(this);
this.updateStatus = this.updateStatus.bind(this);
this.updateContent = this.updateContent.bind(this);
this.removePrison = this.removePrison.bind(this);
this.state = {
currentPrison: {
uuid: null,
prisonName: " ",
address: {
city: " ",
country: " ",
state: " ",
street: " ",
zip: " "
},
rules: " "
},
message: " ",
};
}
componentDidMount() {
console.log(this.props)
this.getPrison(this.props.match && this.props.match.params.uuid);
}
onChangePrisonName(e) {
const prisonName = e.target.value;
this.setState(function (prevState) {
return {
currentPrison: {
...prevState.currentPrison,
prisonName: prisonName,
},
};
});
}
onChangeCity(e) {
var newAddress = {...this.state.currentPrison.address}
address.city = e.target.value;
this.setState(function (prevState) {
return {
currentPrison: {
...prevState.currentPrison,
address: newAddress,
},
};
});
}
onChangeCountry(e) {
var newAddress = {...this.state.currentPrison.address}
address.country = e.target.value;
this.setState(function (prevState) {
return {
currentPrison: {
...prevState.currentPrison,
address: newAddress,
},
};
});
}
onChangeState(e) {
var newAddress = {...this.state.currentPrison.address}
address.state = e.target.value;
this.setState(function (prevState) {
return {
currentPrison: {
...prevState.currentPrison,
address: newAddress,
},
};
});
}
onChangeStreet(e) {
var newAddress = {...this.state.currentPrison.address}
address.street = e.target.value;
this.setState(function (prevState) {
return {
currentPrison: {
...prevState.currentPrison,
address: newAddress,
},
};
});
}
onChangeZip(e) {
var newAddress = {...this.state.currentPrison.address}
address.zip = e.target.value;
this.setState(function (prevState) {
return {
currentPrison: {
...prevState.currentPrison,
address: newAddress,
},
};
});
}
onChangeRules(e) {
const rules = e.target.value;
this.setState((prevState) => ({
currentPrison: {
...prevState.currentPrison,
rules: rules,
},
}));
}
getPrison(uuid) {
PrisonDataService.get(uuid)
.then((response) => {
this.setState({
currentPrison: response.data,
});
console.log(response.data);
})
.catch((e) => {
console.log(e);
});
}
updateStatus(status) {
var address = {
street: this.state.currentPrison.address.street,
state: this.state.currentPrison.address.state,
country: this.state.currentPrison.address.country,
city: this.state.currentPrison.address.city,
zip: this.state.currentPrison.address.zip
}
var data = {
uuid: this.state.currentPrison.uuid,
prisonName: this.state.currentPrison.prisonName,
address: address,
rules: this.state.currentPrison.rules,
};
this.props
.updatePrison(this.state.currentPrison.uuid, data)
.then((response) => {
this.setState((prevState) => ({
currentPrison: {
...prevState.currentPrison,
},
}));
this.setState({ message: "The status was updated successfully!" });
})
.catch((e) => {
console.log(e);
});
}
updateContent() {
this.props
.updatePrison(this.state.currentPrison.uuid, this.state.currentPrison)
.then((response) => {
console.log(response);
this.setState({ message: "The prison was updated successfully!" });
})
.catch((e) => {
console.log(e);
});
}
removePrison() {
this.props
.deletePrison(this.state.currentPrison.uuid)
.then(() => {
this.props.history.push("/prisons");
})
.catch((e) => {
console.log(e);
});
}
render() {
const { currentPrison } = this.state;
return (
<div>
{currentPrison ? (
<div className="edit-form">
<h4>Prison</h4>
<Form>
<FormGroup>
<Label htmlFor="prisonName">Prison Name</Label>
<Input
type="text"
className="form-control"
id="prisonName"
value={currentPrison.prisonName}
onChange={this.onChangePrisonName}
/>
</FormGroup>
{/* {console.log(currentPrison.address)} */}
{/* <FormGroup>
<Label htmlFor="city">City</Label>
<Input
type="text"
className="form-control"
id="city"
value={currentPrison.address.city}
onChange={this.onChangeCity}
/>
</FormGroup>
<FormGroup>
<Label htmlFor="country">Country</Label>
<Input
type="text"
className="form-control"
id="country"
value={currentPrison.address.country}
onChange={this.onChangeCountry}
/>
</FormGroup>
<FormGroup>
<Label htmlFor="state">State</Label>
<Input
type="text"
className="form-control"
id="state"
value={currentPrison.address.state}
onChange={this.onChangeState}
/>
</FormGroup>
<FormGroup>
<Label htmlFor="street">Street</Label>
<Input
type="text"
className="form-control"
id="street"
value={currentPrison.address.street}
onChange={this.onChangeStreet}
/>
</FormGroup>
<FormGroup>
<Label htmlFor="zip">Zip</Label>
<Input
type="text"
className="form-control"
id="zip"
value={currentPrison.address.zip}
onChange={this.onChangeZip}
/>
</FormGroup> */}
<FormGroup>
<Label for="rules">Rules</Label>
<Input
type="text"
className="form-control"
id="rules"
value={currentPrison.rules}
onChange={this.onChangeRules}
/>
</FormGroup>
</Form>
<Button
color="danger"
onClick={this.removePrison}
>
Delete
</Button>
<Button
type="submit"
color="primary"
onClick={this.updateContent}
>
Update
</Button>
<p>{this.state.message}</p>
</div>
) : (
<div>
<br />
<p>Please click on a Prison...</p>
</div>
)}
</div>
);
}
}
export default connect(null, { updatePrison, deletePrison })(Prison);
add-prison.component.js
import React, { Component } from "react";
import { connect } from "react-redux";
import { Button, FormGroup, Label, Input } from "reactstrap";
import { createPrison } from "../../actions/prisons";
class AddPrison extends Component {
constructor(props) {
super(props);
this.onChangeCity = this.onChangeCity.bind(this);
this.onChangeCountry = this.onChangeCountry.bind(this);
this.onChangeState = this.onChangeState.bind(this);
this.onChangeStreet = this.onChangeStreet.bind(this);
this.onChangeZip = this.onChangeZip.bind(this);
this.onChangePrisonName = this.onChangePrisonName.bind(this);
this.onChangeRules = this.onChangeRules.bind(this);
this.savePrison = this.savePrison.bind(this);
this.newPrison = this.newPrison.bind(this);
this.state = {
uuid: null,
address: {
city: " ",
country: " ",
state: " ",
street: " ",
zip: " ",
},
prisonName: " ",
rules: " ",
};
}
onChangeCity(e) {
var newAddress = { ...this.state.address }
newAddress.city = e.target.value
this.setState({
address: newAddress,
});
}
onChangeCountry(e) {
var newAddress = { ...this.state.address }
newAddress.country = e.target.value
this.setState({
address: newAddress,
});
}
onChangeState(e) {
var newAddress = { ...this.state.address }
newAddress.state = e.target.value
this.setState({
address: newAddress,
});
}
onChangeStreet(e) {
var newAddress = { ...this.state.address }
newAddress.street = e.target.value
this.setState({
address: newAddress,
});
}
onChangeZip(e) {
var newAddress = { ...this.state.address }
newAddress.zip = e.target.value
this.setState({
address: newAddress,
});
}
onChangeRules(e) {
console.log(e.target.value)
this.setState({
rules: e.target.value,
})
}
onChangePrisonName(e) {
console.log(e.target.value)
this.setState({
prisonName: e.target.value
})
}
savePrison() {
const { prisonName, address, rules } = this.state;
console.log(address)
this.props
.createPrison(prisonName, address, rules)
.then((data) => {
this.setState({
prisonName: data.prisonName,
address: data.address,
rules: data.rules,
});
console.log(data);
})
.catch((e) => {
console.log(e);
});
}
newPrison() {
this.setState ({
uuid: null,
address: {
city: " ",
country: " ",
state: " ",
street: " ",
zip: " ",
},
prisonName: " ",
rules: "",
});
}
render() {
return (
<div className="submit-form">
{this.state.submitted ? (
<div>
<h4>You submitted successfully!</h4>
<Button color="success" onClick={this.newPrison}>
Add
</Button>
</div>
) : (
<div>
<FormGroup>
<Label htmlFor="prisonName">Prison Name</Label>
<Input
type="text"
className="form-control"
id="prisonName"
required
value={this.state.prisonName}
onChange={this.onChangePrisonName}
name="prisonName"
/>
</FormGroup>
<FormGroup>
<Label htmlFor="city">City</Label>
<Input
type="text"
className="form-control"
id="city"
required
value={this.state.address.city}
onChange={this.onChangeCity}
name="city"
/>
</FormGroup>
<FormGroup>
<Label htmlFor="country">Country</Label>
<Input
type="text"
className="form-control"
id="country"
required
value={this.state.address.country}
onChange={this.onChangeCountry}
name="prison"
/>
</FormGroup>
<FormGroup>
<Label htmlFor="state">State</Label>
<Input
type="text"
className="form-control"
id="state"
required
value={this.state.address.state}
onChange={this.onChangeState}
name="state"
/>
</FormGroup>
<FormGroup>
<Label htmlFor="street">Street</Label>
<Input
type="text"
className="form-control"
id="street"
required
value={this.state.address.street}
onChange={this.onChangeStreet}
name="releaseDate"
/>
</FormGroup>
<FormGroup>
<Label htmlFor="zip">Zip</Label>
<Input
type="text"
className="form-control"
id="zip"
required
value={this.state.address.zip}
onChange={this.onChangeZip}
name="releaseDate"
/>
</FormGroup>
<FormGroup>
<Label htmlFor="rules">Rules</Label>
<Input
type="text"
className="form-control"
id="rules"
required
value={this.state.rules}
onChange={this.onChangeRules}
name="rules"
/>
</FormGroup>
<Button onClick={this.savePrison} color="success">
Submit
</Button>
</div>
)}
</div>
);
}
}
export default connect(null, { createPrison })(AddPrison);