Element type invalid - javascript

I am trying to loop out some partner logos from a headless CMS, but whenever I try to use React-components in my file I get an error stating
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of `Partners`.
I can use my map functions as pure javascript functions but when I try to use them as React components I get this error.
What I want to work
const SinglePartner = ({partner}) => {
return (
<Col sm="6" md="3" lg="4" className="logoScaling">
<h4 className="text-center">{partner.title}</h4>
<img
src={partner.partnerLogo.asset.url}
alt={partner.partnerLogo.alt}
className="partnerLogos"
/>
</Col>
) }
const PartnerLooper = partners.map((partner) => {
return <SinglePartner key={partner._key} /> })
When debugging I tried simplifying my components, re-writing my PartnerLooper to
const PartnerLooper = partners.map((partner) => {
return <p>{partner.name}</p>
})
Using this method I can call PartnerLooper as a javascript function but not as a react component
return(
{/* Returns errror */}
<PartnerLooper />
{/* Works */}
{PartnerLooper}
)
Full component code:
import React from "react";
import { Col, Row } from "react-bootstrap";
const Partners = ({ partners }) => {
const PartnerLooper = partners.map((partner) => {
return <SinglePartner partner={partner} />
})
const SinglePartner = ({partner}) => {
return (
<Col sm="6" md="3" lg="4" className="logoScaling">
<h4 className="text-center">{partner.title}</h4>
<img
src={partner.partnerLogo.asset.url}
alt={partner.partnerLogo.alt}
className="partnerLogos"
/>
</Col>
)
}
return (
<div className="container pt-8 pt-md-10 partnerPadding" role="region">
<section aria-label="Partners">
<Row className="justify-content-md-center">
<PartnerLooper />
</Row>
</section>
</div>
);
};
export default Partners;
See the datastructure I am working with here
https://pastebin.com/MFGh1xuY
EDIT: I am running "gatsby": "^2.22.15" and "react": "^16.12.0",

You're assigning an array of elements to PartnerLooper and then using it as a component <PartnerLooper/> in the Partners component. you can insert an element array directly as a child in JSX.
Replace the returned JSX with
<div className="container pt-8 pt-md-10 partnerPadding" role="region">
<section aria-label="Partners">
<Row className="justify-content-md-center">
{PartnerLooper}
</Row>
</section>
</div>
If you meant to render one Row per partner, <ou can achieve that like this:
return (
<div className="container pt-8 pt-md-10 partnerPadding" role="region">
<section aria-label="Partners">
{partners.map(partner =>
<Row className="justify-content-md-center" key={partner._key}>
<SinglePartner partner={partner} />
</Row>
)}
</section>
</div>
)

Thank you DustInCompetent, your answer helped me
I did not want to run map directly in JSX because I think it is a bit ugly, I solved this by wrapping my SinglePartner and PartnerLooper-components in a parent component and using the return from this component. Full code:
const Partners = ({ partners }) => {
const AllPartners = () => {
const SinglePartner = ({ partner }) => {
return (
<Col sm="6" md="3" lg="4" className="logoScaling">
<h4 className="text-center">{partner.name}</h4>
<img
src={partner.partnerLogo.asset.url}
alt={partner.partnerLogo.alt}
className="partnerLogos"
/>
</Col>
)
}
const PartnerLooper = partners.map((partner) => {
return <SinglePartner partner={partner} />
})
return PartnerLooper
}
return (
<div className="container pt-8 pt-md-10 partnerPadding" role="region">
<section aria-label="Partners">
<Row className="justify-content-md-center">
<AllPartners />
</Row>
</section>
</div>
);
};
export default Partners;

Related

<li> elements missing keys even after assigning unique keys to each element (ReactJS) [duplicate]

I am a beginner at React. I wrote this code and got an Error
import { DoItem } from '../MyComponents/DoItem'
export const ToDo = (props) => {
return (
<div className="container">
<h3 className="text-center">To Do List</h3>
{props.todos.map((todo) => {
return (
<>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</>
)
})}
</div>
)
}
Here's the error Each child in a list should have a unique "key" prop.
I looked online and found that I have to use a key.
I inserted the key
<DoItem const todo={todo} key={todo.nos} onDelete = {props.onDelete} />
But the error still didn't go after I reload the page.
Please add a unique key to every item
{props.todos.map((todo, index) => {
return (
<div key={index}>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</div>
)
})}
Please have a try and let me know if it works or not.
import { DoItem } from '../MyComponents/DoItem'
export const ToDo = (props) => {
return (
<div className="container">
<h3 className="text-center">To Do List</h3>
{props.todos.map((todo, i) => {
return (
<key={i}>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</>
)
})}
</div>
)
}
Yeah, you should add a key prop to anytime you're rendering an Array.
import { DoItem } from '../MyComponents/DoItem'
export const ToDo = (props) => {
return (
<div className="container">
<h3 className="text-center">To Do List</h3>
{props.todos.map((todo,index) => {
return (
<div key={index | the id of the todo}>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</div>
)
})}
</div>
)
}

React Error: Each child in a list should have a unique "key" prop

I am a beginner at React. I wrote this code and got an Error
import { DoItem } from '../MyComponents/DoItem'
export const ToDo = (props) => {
return (
<div className="container">
<h3 className="text-center">To Do List</h3>
{props.todos.map((todo) => {
return (
<>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</>
)
})}
</div>
)
}
Here's the error Each child in a list should have a unique "key" prop.
I looked online and found that I have to use a key.
I inserted the key
<DoItem const todo={todo} key={todo.nos} onDelete = {props.onDelete} />
But the error still didn't go after I reload the page.
Please add a unique key to every item
{props.todos.map((todo, index) => {
return (
<div key={index}>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</div>
)
})}
Please have a try and let me know if it works or not.
import { DoItem } from '../MyComponents/DoItem'
export const ToDo = (props) => {
return (
<div className="container">
<h3 className="text-center">To Do List</h3>
{props.todos.map((todo, i) => {
return (
<key={i}>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</>
)
})}
</div>
)
}
Yeah, you should add a key prop to anytime you're rendering an Array.
import { DoItem } from '../MyComponents/DoItem'
export const ToDo = (props) => {
return (
<div className="container">
<h3 className="text-center">To Do List</h3>
{props.todos.map((todo,index) => {
return (
<div key={index | the id of the todo}>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</div>
)
})}
</div>
)
}

How can I access props from inside a component

I'm trying to access "props" from a component for which I'm passing an object. I'm a bit lost with JS here ; basically what I'm trying to do is to build a Master/Detail view (so show/hide 2 different components based on user clicks on a table).
How can I access "props" from the object rowEvent once a user clicks on a table row ?
const rowEvents = {
onClick: (e, row, rowIndex) => {
console.log(row.itemId);
//this.currentItemId= row.itemId; //////////// THIS DOESNT WORK...
}
};
const TableWithSearch = (props) => {
const { SearchBar } = Search;
const { ExportCSVButton } = CSVExport;
return (
<Card>
<CardBody>
<h4 className="header-title">Search and Export</h4>
<p className="text-muted font-14 mb-4">A Table</p>
<ToolkitProvider
bootstrap4
keyField="itemId"
data={props.data}
columns={columns}
search
exportCSV={{ onlyExportFiltered: true, exportAll: false }}>
{props => (
<React.Fragment>
<Row>
<Col>
<SearchBar {...props.searchProps} />
</Col>
<Col className="text-right">
<ExportCSVButton {...props.csvProps} className="btn btn-primary">
Export CSV
</ExportCSVButton>
</Col>
</Row>
<BootstrapTable
{...props.baseProps}
bordered={false}
rowEvents={ rowEvents }
defaultSorted={defaultSorted}
pagination={paginationFactory({ sizePerPage: 5 })}
wrapperClasses="table-responsive"
/>
</React.Fragment>
)}
</ToolkitProvider>
</CardBody>
</Card>
);
};
And the component looks like this :
render() {
let show;
if (this.props.currentItemId === null){
show = (<TableWithSearch data={this.props.data} />)
}
else {
show = (<DisplayItem />)
}
return (
<React.Fragment>
<Row>
<Col>
{ show }
</Col>
</Row>
</React.Fragment>
)
}
}
Your issue is a bit complex because you seem to be needing to update the prop currentItemId from parent's parent.
You can solve your issue by doing the following:
Move the declaration of rowEvents objects in side TableWithSearch functional component.
In TableWithSearch component, receive a callback say updateCurrentItemId from parent which updates the currentItemId in the parent
In parent component, the currentItemId is being passed from parent(again). So maintain a state for it.
TableWithSearch Component
const TableWithSearch = (props) => {
const { SearchBar } = Search;
const { ExportCSVButton } = CSVExport;
const {updateCurrentItemId} = props; //<--------- receive the prop callback from parent
const rowEvents = {
onClick: (e, row, rowIndex) => {
console.log(row.itemId);
updateCurrentItemId(row.itemId) // <--------- use a callback which updates the currentItemId in the parent
//this.currentItemId= row.itemId; //////////// THIS DOESNT WORK...
},
};
return (
<Card>
<CardBody>
<h4 className="header-title">Search and Export</h4>
<p className="text-muted font-14 mb-4">A Table</p>
<ToolkitProvider
bootstrap4
keyField="itemId"
data={props.data}
columns={columns}
search
exportCSV={{ onlyExportFiltered: true, exportAll: false }}
>
{(props) => (
<React.Fragment>
<Row>
<Col>
<SearchBar {...props.searchProps} />
</Col>
<Col className="text-right">
<ExportCSVButton
{...props.csvProps}
className="btn btn-primary"
>
Export CSV
</ExportCSVButton>
</Col>
</Row>
<BootstrapTable
{...props.baseProps}
bordered={false}
rowEvents={rowEvents}
defaultSorted={defaultSorted}
pagination={paginationFactory({ sizePerPage: 5 })}
wrapperClasses="table-responsive"
/>
</React.Fragment>
)}
</ToolkitProvider>
</CardBody>
</Card>
);
};
Parent Component
class ParentComp extends React.Component {
state = {
curItemId: this.props.currentItemId
}
updateCurrentItemId = (udpatedCurId) => {
this.setState({
curItemId: udpatedCurId
})
}
render() {
let show;
// if (this.props.currentItemId === null){
if (this.state.curItemId === null){
show = (<TableWithSearch data={this.props.data} updateCurrentItemId={this.updateCurrentItemId}/>)
}
else {
show = (<DisplayItem />)
}
return (
<React.Fragment>
<Row>
<Col>
{ show }
</Col>
</Row>
</React.Fragment>
)
}
}
}
this.props should give you access for class components
In addition you should create a bind to the click function so it can correctly resolve this, in the constuctor of the rowEvent

Two imports div in map()

I am thinking about the possibility of embedding two imports among map().
My react code looks like this:
{this.state.dataExample.map(item => (
<ItemsSection nameSection={item.name} />
item.data.map((post, index) => (
<ItemsTasks
key={index}
title={post.name}
/>
))
))}
result:
// from ItemsSection
<div className="items-section-name">
<div className="section-name">{nameSection}</div>
</div>
// from ItemsTasks
<div className="item-data">
<div className="item-title">{title}</div>
<div className="item-data">
<div className="item-title">{title}</div>
</div>
This code should illustrate what I would like to get. Trying to import a separate div for each 'element'. The above code reports a syntax error but I have no idea how I could do it.
From the docs,
A common pattern in React is for a component to return multiple elements. Fragments let you group a list of children without adding extra nodes to the DOM.
You can use Fragment, short syntax <></> (It looks like empty tags),
{
this.state.dataExample.map(item => (
<>
<ItemsSection nameSection={item.name} />
{
item.data.map((post, index) => (
<ItemsTasks
key={index}
title={post.name}
/>
))
}
</>
))
}
or you can import Fragment from react package,
import React, {Fragment} from 'react';
{
this.state.dataExample.map(item => (
<Fragment>
<ItemsSection nameSection={item.name} />
{
item.data.map((post, index) => (
<ItemsTasks
key={index}
title={post.name}
/>
))
}
</Fragment>
))
}
You can use React's Fragment
{
this.state.dataExample.map(item => (
<React.Fragment>
<ItemsSection nameSection={item.name} />
{
item.data.map((post, index) => (
<ItemsTasks
key={index}
title={post.name}
/>
))
}
</React.Fragment>
))
}

React - Each child in array .. unique "key" prop warning

I appear to have a decent understanding of this principal, which allows me to get by, until now. I am applying a key prop to all children of all iterators, and yet I'm still getting this warning.
A FacilitiesContainer is rendering a FacilitiesComponent, which in turn renders a list of Facilities, which renders a list of Courses. A Course does not use an iterator. However, the FacilitiesContainer is passing the FacilitiesComponent through a HOC, which is returning the final component. There's nothing in the HOC that modifies the passed components, so I'm not sure if this is a problem.
// The render method of FacilitiesContainer
render = () => {
let FacilitiesWithSearch = SearchHOC(
BasicSearch,
FacilitiesComponent,
{data: this.state.facilities }
);
return <FacilitiesWithSearch />;
}
class FacilitiesComponent extends Component {
renderFacilities = () => (
this.props.data.map((facilityData, index) =>
<Facility key={index} data={facilityData} />
)
)
render = () => (
<Grid>
<Row>
<Col xs={12} sm={8} smOffset={2} md={8} mdOffset={1}>
{
this.props.data.length > 0
? this.renderFacilities()
: <div>No results</div>
}
</Col>
</Row>
</Grid>
)
}
const Facility = ({ data }) => (
<Panel>
<Panel.Heading>
<Panel.Title>{data.Name}</Panel.Title>
</Panel.Heading>
<Panel.Body>
<Grid>
<Row>
<p><b>Address:</b><br />
{data.Street}<br />
{data.City}, {data.State} {data.Zip}
</p>
<p><b>Phone:</b> {data.Phone}</p>
{
data.Courses.map((courseData, index) =>
<p><Course key={index} data={courseData} /></p>)
}
</Row>
</Grid>
</Panel.Body>
</Panel>
);
You indeed didn't provide keys to p elements here:
{
data.Courses.map((courseData, index) =>
<p><Course key={index} data={courseData} /></p>)
}
Should be
{
data.Courses.map((courseData, index) =>
<p key={index}><Course data={courseData} /></p>)
}
Try to append a string to the index before assigning it to the key. That's because you are only using index (0,1,2...) both for your list of facilities and list of courses, so there will be duplicated indexes in the final rendered component. If you do as below you ensure that each index is unique:
<Facility key={`facility_${index}`} data={facilityData} />
and
<Course key={`course_${index}`} data={courseData} />

Categories