I am trying to make form project. When person submmit to personal info to form. I want add this info to Table. But I get this error when I am adding info to table.
Uncaught Error: Objects are not valid as a React child (found: object with keys {inputValue}). If you meant to render a collection of children, use an array instead.
I know this is related to const newToTable part. But I don't know how to make it right. Please help me, ıf you know how can ı solve this problem.
This is my contact.js
const buttonOnClick = () => {
if (inputValue === "" || emailValue === "" || phoneNumberValue === "") {
setShowModal(false);
} else {
setShowModal(true);
// setInputValue("");
//setEmailValue("");
//setPhoneValue("");
// sa
}
const newToTable = [...addFormData, { fullName:{inputValue},email:{emailValue}, phoneNumber:{phoneNumberValue},country:{countryValue} }];
setAddFormData(newToTable);
console.log(`Form submitted, ${showModal}`);
}
This is my AddTable.js
<div className="app-container">
<form>
<Table>
<thead>
<tr>
<th>Full Name</th>
<th>Email </th>
<th>Phone Number</th>
<th>Country</th>
</tr>
</thead>
<tbody>
{addFormData.map((addForm) => (
<tr>
<td>{addForm.fullName}</td>
<td>{addForm.email}</td>
<td>{addForm.phoneNumber}</td>
<td>{addForm.counry}</td>
</tr>
))}
</tbody>
</Table>
</form>
</div>
You've accidently wrapped your form values in objects here:
const newToTable = [...addFormData, { fullName:{inputValue},email:{emailValue}, phoneNumber:{phoneNumberValue},country:{countryValue} }];
For example fullName:{inputValue} will evalute to fullName: { inputValue: 'the value' }
Instead you need:
const newToTable = [
...addFormData,
{
fullName: inputValue,
email: emailValue,
phoneNumber: phoneNumberValue,
country: countryValue,
},
];
This is what the error means by Objects are not valid as a React child - when it tries to render your table, the values being passed are objects such as { inputValue: 'the value' } (this is the (found: object with keys {inputValue}) part of the error - an object with inputValue as a key).
Related
I'm very new to React, and I'm trying to make a table using react that displays information about a car. Currently, I'm trying to implement two buttons on each row that would increment/decrement a certain field of the table.
This is the code for the table:
render() {
return (
<table>
<tr>
<th>Manufacturer</th>
<th>Model</th>
<th>Year</th>
<th>Stock</th>
<th>Price</th>
<th>Options</th>
<th></th>
</tr>
{
this.state.cars.map(car =>
<tr key={car.model}>
<td>{car.manufacturer}</td>
<td>{car.model}</td>
<td>{car.year}</td>
<td>{car.stock}</td>
<td>${car.price}</td>
<td><button type="button" onClick={this.increaseStock.bind(this)}>Increment</button></td>
<td><button type="button" onClick={this.decreaseStock.bind(this)}>Decrement</button></td>
</tr>
))
}
</table>
);
};
This so far is just fine for displaying the data and buttons, however, I'm not actually sure how to implement the buttons' functions
All the implementations for increaseStock and decreaseStock so far have done nothing on click, although I think they're being called. I'm trying to get it to either add to the stock value or subtract from it(not going below 0).
I've tried things using states, but I'm not really sure how those work.
Here's an example of how your component could be implemented. I used the functional component and a state hook because those are what I'm familiar with.
import React, { useState } from "react";
export default function CarTable() {
const [cars, setCars] = useState([
{ id: 1, name: "Car 1", stock: 5 },
{ id: 2, name: "Car 2", stock: 10 }
]);
const increase = (index) => {
const oldCar = cars[index];
// copying the car with the updated stock
const newCar = { ...oldCar, stock: oldCar.stock + 1 };
//copying the car array
const newCars = [...cars];
//replacing the old car with a new one in a new array
newCars[index] = newCar;
//updating state
setCars(newCars);
};
const decrease = (index) => {
// same as above except decreasing the stock now
const oldCar = cars[index];
const newCar = { ...oldCar, stock: oldCar.stock - 1 };
const newCars = [...cars];
newCars[index] = newCar;
setCars(newCars);
};
return (
<table>
<thead>
<tr>
<th>name</th>
<th>stock</th>
<th></th>
</tr>
</thead>
<tbody>
{cars.map((car, i) => (
<tr key={car.id}>
<td>{car.name}</td>
<td>{car.stock}</td>
<td>
<button onClick={() => increase(i)}>increase</button>
<button onClick={() => decrease(i)}>decrease</button>
</td>
</tr>
))}
</tbody>
</table>
);
}
In short what you need to do is create a new car object with the updated stock property. Then create a new cars array with the new car object just mentioned and then set the state to this new cars array.
Here's also a CodeSandbox link where you can try it out:
https://codesandbox.io/s/charming-dijkstra-8brqz1?file=/src/CarTable.js
Hope that helps.
I have an object:
{
cities: {
MCR: "Manchester",
LDN: "London",
NYC: "New York"
}
}
and I want to iterate over these and display them in a table format which will show the city code and the long name next to it. Something like:
<tbody>
<tr>
<th>City Code</th>
<th>City Name</th>
</tr>
<tr>
{Object.entries(cities).map(([key, value]) => {
<>
<td>{key}</td>
<td>{value}</td>
</>
}
)}
</tr>
</tbody>
However this doesn't display anything and also shows an error when hovering over value:
Type 'unknown' is not assignable to type 'ReactNode'.ts(2322)
I'm quite new to React and wondering how best to display this information?
Thanks
let say you have an object as:
const obj = {
cities: {
MCR: "Manchester",
LDN: "London",
NYC: "New York"
}
};
It would be better to loop over cities and create a new tr so that It looks like a table
CODESANDBOX LINK
You want to map over the cities then you should return it from map as:
<tbody>
<tr>
<th>City Code</th>
<th>City Name</th>
</tr>
{ Object.entries( obj.cities ).map( ( [key, value] ) => {
return ( // PROBLEM SHOULD RETURN
<tr>
<td>{ key }</td>
<td>{ value }</td>
</tr>
);
}
) }
</tbody>
You need to return the result in each iteration. Also, each iteration would return a tr with a key prop:
{
Object.entries(obj.cities).map(([key, value]) => (
<tr key={key}>
<td>{key}</td>
<td>{value}</td>
</tr>
))
}
Note: since city is a key in an object, you'll need to access it as above
You are just missing the return in your map's callback function. Always remember to include a return in your arrow functions when using it like this: () => {}. It is easy to miss because ()=>() would return whatever you write in the second () but in the former example this is not true.
I am trying to render an object held in state. The contents of this.state is:
"statement": {
"creator": "8ff243b2-f21e-43f3-9090-4aa679fbeb1a",
"id": "bf4c965e-bd59-48c8-b31a-8f67529e5fde",
"impactors": [
"978388e8-2987-4c89-82b6-4da619d82935",
"1d75e2a7-bf2a-4f55-ba68-373752b24f98"
],
"score": {
"impactors": 2,
"net": 3,
"percentage": 0.75,
"total_votes": 4
},
"statement": "The Earth is round."
}
In my React JS app, I am able to render some of the child object (statement) but not all. Here is my code:
renderStatement() {
return (
<tbody>
<tr>
<td>Statement: </td>
<td>{this.state.statement.score}</td>
</tr>
</tbody>
)
}
As expected, the above code returns an error: Error: Objects are not valid as a React child (found: object with keys {impactors, net, percentage, total_votes}). If you meant to render a collection of children, use an array instead.
What I actually want is percentage, which is a node underneath score. When I try to drill down and have it just render percentage, like this:
renderStatement() {
return (
<tbody>
<tr>
<td>Statement: </td>
<td>{this.state.statement.score.percentage}</td>
</tr>
</tbody>
)
}
I get the following error: TypeError: Cannot read property 'percentage' of undefined.
Any of the other objects ('creator', 'id', 'impactors', 'statement') work just fine.
This is how I fixed it:
renderStatement() {
const score = this.state.statement.score || {}
return (
<tbody>
<tr>
<td>Statement: </td>
<td>{score.percentage}</td>
</tr>
</tbody>
)
}
you can do the following:
renderStatement() {
const text = (typeof this.state.statement.score !== "undifined") ?
this.state.statement.score.percentage : ''
return (
<tbody>
<tr>
<td>Statement: </td>
<td>{text}</td>
</tr>
</tbody>
)
}
fakeMovieService.js:
const movies = [
{
_id: "5b21ca3eeb7f6fbccd471815",
title: "Terminator",
genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
numberInStock: 6,
dailyRentalRate: 2.5,
publishDate: "2018-01-03T19:04:28.809Z"
},
//and a few more movie objects of the same format
];
export function getMovies() {
return movies;
}
movies.js
import React, { Component } from "react";
import { getMovies } from "../services/fakeMovieService";
class Movies extends Component {
state = {
movies: getMovies(),
};
render() {
return (
<div>
<div className="jumbotron text-center">
<div className="container">
<h1>Vidly</h1>
</div>
</div>
<h1>Vidly</h1>
<table className="table">
<thead>
<tr>
<th scope="col">Title</th>
<th scope="col">Genre</th>
<th scope="col">Stock</th>
<th scope="col">Rate</th>
</tr>
</thead>
<tbody>
{this.state.movies.map((element) => (
<tr key={element._id}>
<th scope="col">{element.title}</th>
<th scope="col">{element.genre}</th>
<th scope="col">{element.numberInStock}</th>
<th scope="col">{element.dailyRentalRate}</th>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
export default Movies;
I'm getting this error:
react-dom.development.js:13413 Uncaught Error: Objects are not valid as a React child (found: object with keys {_id, name}). If you meant to render a collection of children, use an array instead.
I know we're supposed to get this error when you return an object as it is without having any of the "tags", but I've checked my code and it doesn't seem like I'm returning an object as it is.
element.genre is an object and you are actually trying to render it explicitly.
<th scope="col">{element.genre}</th> // here your code fails
You could e.g. point directly to the name field inside element.genre object to compile successfully.
<th scope="col">{element.genre.name}</th>
I am getting "Uncaught TypeError: this.state.data.map is not a function" error even I can successfully log data to console from the API.
I have found similar questions but, haven't come up with a good solution to solve this issue yet.
I have read here that, "Objects, {}, in JavaScript does not have the method .map(), it's only for Arrays, []."
However, I can not figure out how to fix this issue, iterate over an object and retrieve data to the React front end too.
Thank you and any help would be greatly appreciated.
import React, { Component } from "react";
import axios from "axios";
export default class GetSubjects extends Component {
constructor(props) {
super(props);
this.getsubjects = this.getsubjects.bind(this);
this.onSearch = this.onSearch.bind(this);
this.state = {
keyword: "",
data: []
};
}
getsubjects(e) {
this.setState({ keyword: e.target.value });
}
onSearch(e) {
e.preventDefault();
const searchsub = {
keyword: this.state.keyword
};
axios
.get(`http://localhost:3000/api/messages/courses/${this.state.keyword}`)
.then(response => {
console.log(response);
this.setState({
data: response.data
});
});
console.log(this.state.keyword);
console.log(this.state.data);
}
componentDidMount() {}
render() {
return (
<div>
<br />
<div>
<label>Course Name</label>{" "}
<input
placeholder="Enter Course Name"
type="text"
value={this.state.keyword}
onChange={this.getsubjects}
name="keyword"
required
/>{" "}
<button className="btn btn-primary" onClick={this.onSearch}>
Get Subjects
</button>
</div>
<br />
<table className="table table-bordered">
<thead>
<tr>
<th scope="col">Course Name</th>
<th scope="col">Subjects</th>
</tr>
</thead>
<tbody>
{this.state.data.map(function(subject) {
return (
<tr>
{" "}
<td key={subject.id}>{subject.name}</td>{" "}
<td key={subject.id}>{subject.subjects}</td>{" "}
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}
You've said what you're receiving is:
{
"subjects": ["Computer Architecture", "Basic Networking"],
"_id": "5cf368bfb58f8c35bc19cebc",
"name": "Software Engineering",
"passmark": 75,
"lectureIncharge": "John Smith",
"__v": 0
}
Your setState call sets data to that object, which is not an array.
Your render code expects that to be an array, though. It tries to loop through it and use it to fill in rows in a table. But you're only getting one piece of data: A single course ("Software Engineering") which covers two subjects ("Computer Architecture" and "Basic Networking").
So your render code shouldn't be trying to use that as an array (and so you may not want a table anymore). It should just use data's name and subjects properties directly.
I'll keep your table markup for now, but note that this only produces a single row (because there's only one piece of data). Prior to the return, I'd grab the course:
const course = this.state.data;
then where you're outputting your table:
<tbody>
{course && course.name
? undefined
:
<tr>
<td key={course.id}>{course.name}</td>{" "}
<td key={course.id}>{course.subjects.join(", ")}</td>{" "}
</tr>
}
</tbody>
I've used an explicit join(", ") to join the subjects rather than implicitly via toString, which wouldn't include a space after the comma.
response.data is an object which axios fills when the request is done.
It's true you're initializing data as an array, but when you do:
this.setState({ data: response.data }); You've actually changed it to an object.
Parse the object you get to an array or do something else with the returned data.
Edit: After you response: just do: this.setState({data: response.data.subject});
//yo lo solucione poniendo data.data
//porque (data) solo me devolvía un objeto con varios atributos y data era uno de esos
//entonces le agregue data.data.
getCategorias(){
axios.get("http://localhost:8000/api/categorias")
.then(data => {
this.setState({
data: data.data
});
}).catch((error)=>{
console.error(error)
});
}
componentDidMount(){
this.getCategorias();
}