Objects are not valid as a React child use an array instead - reactjs

I'm getting "Objects are not valid as a React child" on this block:
<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>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{movies.filter(movie => (
<tr key={movie._id}>
<td>{movie.title}</td>
<td>{movie.genre.name}</td>
<td>{movie.numberInStock}</td>
<td>{movie.dailyRentalRate}</td>
<td>
<Like
onClick={() => this.handleLike(movie)}
liked={movie.liked}
/>
</td>
<td>
<button
onClick={() => this.handleDelete(movie._id)}
className="btn btn-danger m-2"
>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
The exact error message reads: Error: Objects are not valid as a React child (found: object with keys {_id, title, genre, numberInStock, dailyRentalRate, publishDate, liked}). If you meant to render a collection of children, use an array instead.
No matter what I do to troubleshoot this the error won't go away. Can anyone explain ?

This:
<tbody>
{movies.map(movie => (
<tr key={movie._id}>
<td>{movie.title}</td>
<td>{movie.genre.name}</td>
<td>{movie.numberInStock}</td>
<td>{movie.dailyRentalRate}</td>
<td>
<Like
onClick={() => this.handleLike(movie)}
liked={movie.liked}
/>
</td>
<td>
<button
onClick={() => this.handleDelete(movie._id)}
className="btn btn-danger m-2"
>
Delete
</button>
</td>
</tr>
))}
</tbody>
Should look like this:
<tbody>
<MovieComponent
movie={movie}
likeOnCLick={this.handleLike(movie)}
/>
</tbody>
You're not filtering anything, so just use map(), and pass the results into a React.Component that you define elsewhere.

The filter method is used to select certain items of an array. It seems that you have confused this with the map method, which should work in this scenario.
filter: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
map: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

Related

How can I align Products and Show Filter on one line? How can I make the filter button work so it shows the input values by product and price below?

I need to align the "Products" and a "Show filter" button on one line and space between them. I need to add classNames because it's a crud app built with react and using bootstrap. And when I press "show filter" it should change to "hide filter" and show us input values filtering the table by products and price range.
For the Header and the button, I created a new div but I think it must be done in another way.
How can I fix it and then make the filter button functional?
``` return(
<div className='container'>
<h1 className='block'>Products</h1>
<button className='btn btn-light block'>Show Filter</button>
<table className="table">
<thead>
<tr className='bg-dark text-white'>
<th scope="col">#</th>
<th scope="col">Product Name</th>
<th scope="col">Product Number</th>
<th scope="col">Color</th>
<th scope="col">List Price</th>
<th scope="col">Modified Date</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>{products.map((product,index)=>(
<tr key={product.id}>
<th scope="row">{index + 1}</th>
<td>{product.name}</td>
<td>{product.number}</td>
<td>{product.color}</td>
<td>{product.price}</td>
<td>{product.date}</td>
<td>
{/* <Link className='btn btn-primary m-2'><i className="fa fa-eye" aria-hidden="true"></i></ Link> */}
<Link className='btn btn-secondary m-2' to={`/product/edit/${product.id}`}>Edit</Link>
<Link className='btn btn-danger m-2' onClick={()=>{deleteUSer()}}>Delete</Link>
</td>
</tr>
))}
</tbody>
</table>
<Link className='btn btn-outline-dark w-25' to='/product/add'>
Add Product
</Link>
</div>
);
}
export default Products; ```

React/Typescript Can't render a React.Fragment inside <tbody>:

I am trying to use a map to render <tr> elements within a <tbody>. This conditionally will render a second <tr> if there is additional content to be displayed under first <tr>. I have wrapped both in a React.Fragment and this is working fine, but when running the tests I get:
Warning: validateDOMNesting(...): %s cannot appear as a child of <%s>.%s%s%s
Table:
<table className='document-table borderless row-height-sm'>
<thead>
<tr>
{tableData.headers.map((th) => (
<th key={`document-table-th-${th.value}`}>{intl.formatMessage(th.descriptor, { value: th.value })}
<button onClick={() => { sortRows(th.value) }} className='ghost'>
<Icon data-ref="action-item-chevron" role="img" name='sort' aria-label="Sort arrows" />
</button>
</th>
))}
</tr>
</thead>
<tbody>
{sortedTableRows.map((tr, i) => (
<DocumentTableRow
key={tr.id}
rowData={tr}
rowIndex={i}
openRows={openRows}
setOpenRows={setOpenRows}
/>
))}
</tbody>
</table>
Table Row:
return (
<React.Fragment>
<tr key={`document-table-tr-${rowData.id}`}>
{rowData.values.map((td, j) => (
<td className={`document-table-td-${j} ${j === rowData.values.length - 1 ? 'flex align-items-center justify-content-space' : ''}`} key={`document-table-td-${td.sortKey.replace(' ', '-')}`}>
{intl.formatMessage(td.descriptor, {value: td.value})}
{j === rowData.values.length - 1 &&
<button onClick={() => { rowData.additionalContent && rowData.additionalContent.value ? setOpenRow(rowIndex) : null }} className='ghost'>
<Icon data-ref={`document-table-row-${rowIndex}`} role="img" name={`chevron-${openRows[rowIndex] ? 'up' : 'down'}`} aria-label="Expand row" />
</button>
}
</td>
))}
</tr>
{rowData.additionalContent && rowData.additionalContent.value && openRows[rowIndex] &&
<tr className='additional-content'><td className='pad-left-xl'>{rowData.additionalContent.value}</td></tr>
}
</React.Fragment>
);
};
Rendered html:
<table class="document-table borderless row-height-sm">
<thead>
<tr>
<th>Document type</th>
<th>Jurisdiction</th>
<th>Upload date</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td class="document-table-td-0 ">Passport</td>
<td class="document-table-td-1 ">Germany</td>
<td class="document-table-td-2 ">Uploaded 2021-10-12</td>
<td class="document-table-td-3 flex align-items-center justify-content-space">Rejected</td>
</tr>
<tr class='additional content'>
<td>Rejected due to expiration</td>
</tr>
</tbody>
Why is it complaining about DOM nesting when the rendered html is valid, and why only in tests and not when rendering the component in the application?

How to restrict Table Header to display once in map function?

I have a data store in state which needs to be displayed in a tabular format in UI using React. I am using a map function to display the data.
I am able to display the data but the header is being displayed after each row as they are iterated in a loop.
Please let me know how can i display the output in tabular format with header being displayed only once?
return method code in React:-
return (
<div>
<br />
<input
type="submit"
class="btn btn-info btn-sm"
value="Create Itinerary"
onClick={this.callItinAPI}
/>
<br />
<br />
{this.state.ItinData.map((item) => (
<div>
<table id="DisplayRequest">
<tr>
<th>TripName</th>
<th>Booking ID</th>
<th>Start Date</th>
<th>End Date</th>
</tr>
<tr>
<td>{item.Itinerary.TripName._text}</td>
<td>{item.Itinerary.Bookings.Booking.RecordLocator._text}</td>
<td>{item.Itinerary.StartDateLocal._text}</td>
<td>{item.Itinerary.EndDateLocal._text}</td>
</tr>
</table>
</div>
))}
</div>
);
Expected output:- Table header to displayed only once followed by all the data rows
You just need to extract the header from your loop :
<div>
{this.state.ItinData.length > 0 ? (
<table id={'DisplayRequest'}>
<tr>
<th>TripName</th>
<th>Booking ID</th>
<th>Start Date</th>
<th>End Date</th>
</tr>
{this.state.ItinData.map((item) => (
<tr>
<td>{item.Itinerary.TripName._text}</td>
<td>{item.Itinerary.Bookings.Booking.RecordLocator._text}</td>
<td>{item.Itinerary.StartDateLocal._text}</td>
<td>{item.Itinerary.EndDateLocal._text}</td>
</tr>
))}
</table>;
) : null}
</div>
return (
<div>
<br />
<input
type="submit"
class="btn btn-info btn-sm"
value="Create Itinerary"
onClick={this.callItinAPI}
/>
<br />
<br />
<div>
<table id="DisplayRequest">
<tr>
<th>TripName</th>
<th>Booking ID</th>
<th>Start Date</th>
<th>End Date</th>
</tr>
{this.state.ItinData.map((item) => (
<tr>
<td>{item.Itinerary.TripName._text}</td>
<td>{item.Itinerary.Bookings.Booking.RecordLocator._text}</td>
<td>{item.Itinerary.StartDateLocal._text}</td>
<td>{item.Itinerary.EndDateLocal._text}</td>
</tr>
))}
</table>
</div>
</div>
);
just move that td out side the loop
The issue with your code is, you have put the table header in the loop itself which is wrong. Try something like this:
{
( this.state.ItinData.length > 0 ) // conditional rendering if data exist
?
<table id={'DisplayRequest'}>
<tr>
<th>TripName</th>
<th>Booking ID</th>
<th>Start Date</th>
<th>End Date</th>
</tr>
// Use the map() function to iterate the array and display the table body here
{this.state.ItinData.map((item) => (
<tr>
<td>{item.Itinerary.TripName._text}</td>
<td>{item.Itinerary.Bookings.Booking.RecordLocator._text}</td>
<td>{item.Itinerary.StartDateLocal._text}</td>
<td>{item.Itinerary.EndDateLocal._text}</td>
</tr>
))}
</table>
null
}

Render Modal for Dynamic Table in React

I have a dynamic table whose items I render through a list. The idea is that, on clicking the name of a row, a modal will open and that will print certain values retrieved from the backend server.
When I click on a specific person's name, the modal loads for all elements in the table. How do I fix this?
The rendered code for the table is as follows:-
<table className="table">
<thead>
<tr>
<th>S. NO.</th>
<th>NAME</th>
<th>ADDRESS</th>
<th>TELEPHONE</th>
<th>EMAIL</th>
<th>AGE</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.personData.map((pRow, idx) => (
<>
<PopUp hideModal={this.hideModal} show={this.state.show} id={siteRow.id} />
<tr key={pRow.id}>
<td>{idx + 1}</td>
<td> <a onClick={this.showModal}> {pRow.name} </a> </td>
<td>{pRow.address}</td>
<td>{pRow.phone}</td>
<td>{pRow.email}</td>
<td>{pRow.age}</td>
<td>
{" "}
<DeleteButton id={pRow.id} onDelete={this.onDelete} />{" "}
</td>
</tr>
</>
</tbody>
</table>
In the code for the table, the placement of the PopUp component is such because I want to pass the ID of the particular site to the modal.
This is the rendered code for the modal:-
showModal(e) {
this.setState({
show: true
});
}
hideModal(e) {
this.setState({
show:false
});
this.props.hideModal && this.props.hideModal(e);
}
render() {
if(!this.props.show){
return null;
}
return (
<>
<div>
The ID of the person is: {this.props.id}
<button type="button" className="btn theButton" onClick={this.hideModal}>CLOSE</button>
</div>
</>
);
}
This is very rudimentary code and I haven't added much CSS so this just opens up in the table itself. I want to change this but given the placement of the PopUp component and the fact that I want to pass the ID to the component, I'm not sure how to go about it.
The problem is that you have a series of Popups, but only a variable controlling their visibility. Consider replacing the show state as a simple visibility with a showId one, meant as the "id" of the Popup to be shown.
showModal(id) {
this.setState({
showId: id
});
}
hideModal(e) {
this.setState({
showId: null
});
this.props.hideModal && this.props.hideModal(e);
}
Then:
<table className="table">
<thead>
<tr>
<th>S. NO.</th>
<th>NAME</th>
<th>ADDRESS</th>
<th>TELEPHONE</th>
<th>EMAIL</th>
<th>AGE</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.personData.map((pRow, idx) => (
<>
<PopUp hideModal={this.hideModal} show={this.state.showId === pRow.id} id={siteRow.id} />
<tr key={pRow.id}>
<td>{idx + 1}</td>
<td> <a onClick={() => this.showModal(pRow.id)}> {pRow.name} </a> </td>
<td>{pRow.address}</td>
<td>{pRow.phone}</td>
<td>{pRow.email}</td>
<td>{pRow.age}</td>
<td>
{" "}
<DeleteButton id={pRow.id} onDelete={this.onDelete} />{" "}
</td>
</tr>
</>
</tbody>
</table>
I did not try the code, but I think it should work.

Getting 'Parse Error: Adjacent JSX elements must be wrapped in an enclosing tag' even when I use React.Fragment

I have a react component that renders a table. This is the code for render :-
<>
<table className="table">
<thead>
<tr>
<th>S. NO.</th>
<th>NAME</th>
<th>ADDRESS</th>
<th>TELEPHONE</th>
<th>EMAIL</th>
<th>AGE</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.personData.map((pRow, idx) => (
<tr key={pRow.id}>
<td>{idx + 1}</td>
<td data-toggle="modal" data-target="#myModal">{pRow.name}</td>
<td>{pRow.address}</td>
<td>{pRow.phone}</td>
<td>{pRow.email}</td>
<td>{pRow.age}</td>
<td>
{" "}
<DeleteButton
id={pRow.id}
onDelete={this.onDelete}
/>{" "}
</td>
</tr>
</tbody>
</table>
</>
I'm getting
Syntax error: Adjacent JSX elements must be wrapped in an enclosing
tag. Did you want a JSX fragment <>...? (123:4)
Here, line 123 is the line containing ''. What am I doing wrong here? I'm confused
Try this. Your map is not closed.
<>
<table className="table">
<thead>
<tr>
<th>S. NO.</th>
<th>NAME</th>
<th>ADDRESS</th>
<th>TELEPHONE</th>
<th>EMAIL</th>
<th>AGE</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.personData.map((pRow, idx) => (
<tr key={pRow.id}>
<td>{idx + 1}</td>
<td data-toggle="modal" data-target="#myModal">{pRow.name}</td>
<td>{pRow.address}</td>
<td>{pRow.phone}</td>
<td>{pRow.email}</td>
<td>{pRow.age}</td>
<td>
{" "}
<DeleteButton
id={pRow.id}
onDelete={this.onDelete}
/>{" "}
</td>
</tr>
))} // MISSING PROPER CLOSING HERE
</tbody>
</table>
</>
In this particular example, you just forgot to close the map method within <tbody>...</tbody>
It should be:
<tbody>
{this.state.personData.map((pRow, idx) => (
<tr key={pRow.id}>
<td>{idx + 1}</td>
<td data-toggle="modal" data-target="#myModal">{pRow.name}</td>
<td>{pRow.address}</td>
<td>{pRow.phone}</td>
<td>{pRow.email}</td>
<td>{pRow.age}</td>
<td>
{" "}
<DeleteButton
id={pRow.id}
onDelete={this.onDelete}
/>{" "}
</td>
</tr>
))}
</tbody>

Resources