I'm getting an error that i'm missing key prop for my map iteration.Got confused where i'm missing one . I have a map inside map.Could you please help me
displayData() {
const { data, index } = this.state;
let sortedData = data[index].settings.map((item, id) => {
const { _init_ } = item.settings;
return _init_.map((message, index) => {
const { message_content } = message;
return message_content === undefined ? null : (
<>
<div>
<div key={index} className="settings-message">
{message_content}
</div>
</div>
<div>yes</div>
</>
);
});
});
return sortedData;
}
The key should be on the parent div.
return message_content === undefined ? null : (
<div key={index}>
<div className="settings-message">
{message_content}
</div>
</div>
)
Your top level component needs a unique key. Use explicit fragment syntax and add the key to the fragment,
displayData() {
const { data, index } = this.state;
let sortedData = data[index].settings.map((item, id) => {
const { _init_ } = item.settings;
return _init_.map((message, index) => {
const { message_content } = message;
return message_content === undefined ? null : (
<React.Fragment key={index}>
<div>
<div className="settings-message">{message_content}</div>
</div>
<div>yes</div>
</React.Fragment>
);
});
});
return sortedData;
}
ps. You may have one more div than you actually need
Related
I have the following arrays iterated and I'm able to console.log the result I want.
import React from 'react';
const MyApplications = ({ currentUser, jobs, jobApplications }) => {
const jobAppsFromCurrentUser = jobApplications.filter(jobApp => jobApp.musician_id === currentUser.id)
return (
<div>
<div>
{
jobs.filter(job => {
jobAppsFromCurrentUser.map(jobApp => {
if (jobApp.job_id === job.id) {
console.log(job)
}
})
})
}
</div>
</div>
)
}
export default MyApplications
Result:
But ultimately, I need to render each job as jsx. I want to be able to do something like this (this doesn't return anything):
<div>
{
jobs.filter(job => {
jobAppsFromCurrentUser.map(jobApp => {
if (jobApp.job_id === job.id) {
return (
<div>
<h1>{job.title}</h1>
</div>
)
}
})
})
}
</div>
Solution:
import React from 'react';
const MyApplications = ({ currentUser, jobs, jobApplications }) => {
const jobAppsFromCurrentUser = jobApplications.filter(jobApp => jobApp.musician_id === currentUser.id)
const includesID = (id) => {
const onFilter = jobAppsFromCurrentUser.filter((jobApp) => jobApp.job_id == id);
return onFilter.length > 0 ? true : false;
};
return (
<div>
<div>
{jobs.map((job) => {
if (includesID(job.id)) {
return (
<div key={job.id}>
<h1>{job.title}</h1>
</div>
);
}
})}
</div>
</div>
)
}
export default MyApplications
First check if the ID's match.
const includesID = (id) => {
const onFilter = jobs.filter((item) => item.id == id);
return onFilter.length > 0 ? true : false;
};
And render it as
<div>
{jobAppsFromCurrentUser.map((jobApp) => {
if (includesID(jobApp.id)) {
return (
<div>
<h1>{job.title}</h1>
</div>
);
}
})}
</div>
I am trying to use a forEach loop to return a component for each item in an array. However, when my react app loads it just returns [Object] over and over again. Why is this and how do I fix it?
Here is the code:
const ProductList = () => {
let product_image;
let product_heading;
let product_listbox_options = "";
info.data.products.edges.forEach((edge) => {
console.log(edge);
const product = edge.node;
product_heading = edge.node.title;
if (
product.media !== undefined &&
product.media.edges !== undefined &&
product.media.length > 0
) {
product.media.edges.forEach((media) => {
if (media.node.mediaContentType === "IMAGE") {
product_image = (
<Thumbnail
source={media.node.image.originalSrc}
alt={product.title}
/>
);
}
});
}
product_listbox_options += (
<Listbox.Option>
<Heading>{product_heading}</Heading>
{product_image}
</Listbox.Option>
);
});
return product_listbox_options;
};
What you are doing here
product_listbox_options += (
<Listbox.Option>
<Heading>{product_heading}</Heading>
{product_image}
</Listbox.Option>
);
is you are adding an empty string value to a react component which results in [Object].
As #tieulinh said you should use .map() instead of .forEach() if you want to return a list/array of components which can be rendered by react.
So your component becomes like this:
const ProductList = () => {
let product_image;
let product_heading;
return (
<>
{info.data.products.edges.map((edge, index) => {
const product = edge.node;
product_heading = edge.node.title;
if (
product.media !== undefined &&
product.media.edges !== undefined &&
product.media.length > 0
) {
product.media.edges.forEach((media) => {
if (media.node.mediaContentType === "IMAGE") {
product_image = (
<Thumbnail
source={media.node.image.originalSrc}
alt={product.title}
/>
);
}
});
}
return (
//Change this key to something meaningful from your edge object
<Listbox.Option key={index}>
<Heading>{product_heading}</Heading>
{product_image}
</Listbox.Option>
);
})}
</>
);
};
Try doing it this way:
console.log(JSON.stringify(edge, null, 2))
ReactJS doesn't work like this
You can use the map method instead of forEach
I am using React map and I am getting the following error
TypeError: Cannot read property 'PreviewThemeSideBar' of undefined
I don't understand in any way why I get undefined because I checked the imported component where I pass props and there I get all the data, see
SeleceColorsTheme.js
export default function SelectColorsTheme(props) {
const groupSize = 3;
const [selectedIndex, setSelectedIndex] = useState(false);
const setBorder = (index) => {
setSelectedIndex(index);
};
const rows = SideBarColors.map(function (col, index) {
const selectBorder = classNames({
'builtin_theme_preview': true,
'selectBorder': index === selectedIndex ? 'selectBorder' : null
});
// map content to html elements
return <SelectThemeContent {...props} selectBorder={selectBorder}
col={col} setBorder={setBorder} index={index}/>
}).reduce(function (r, element, index) {
// create element groups with size 3, result looks like:
// [[elem1, elem2, elem3], [elem4, elem5, elem6], ...]
index % groupSize === 0 && r.push([]);
r[r.length - 1].push(element);
return r;
}, []).map(function (rowContent) {
// surround every group with 'row'
return <div className="SelectThemePictures_Separator">{rowContent}</div>;
});
return <div className="container">{rows}</div>;
};
SelectThemeContent.js
export default function SelectThemeContent(props) {
const selectBorder = props.selectBorder;
const col = props.col;
const setBorder = props.setBorder;
const index = props.index;
return(
<div className={selectBorder} key={index} onClick={() => props.SideBarPageContent(col) || setBorder(index)}>
<div style={{ background: col.PreviewThemeSideBar }} className="builtin_theme_preview__nav">
<div className="builtin_theme_preview__search" />
...
</div>
</div>
);
}
I just added a check condition to each props, example
<div style={{ background: col && col.PreviewThemeSideBar }}</div>
I'm new in React. I'm developing a screen but I have a issue, I don't know how insert the children in the parent if the state condition is equals, I'm using an array to print the parent and children but depends of the data the parent could have a children or not, for example if (parent.rework_name === children.rework_name) ? print the children : 'nothing in the parent'.
Please let me know if you have an idea how to solve this, many many thanks in advance.
This is the goal, my code works but the damn children is outside the parent :(
class Filling extends Component {
constructor() {
super();
this.state = {
fillingStations: [],
};
}
componentDidMount() {
getDataAPI('http://localhost:8080/api/parent')
.then((station) => {
getDataAPI('http://localhost:8080/api/children')
.then((data) => {
const stationArray = [];
station.map((item, index) => {
stationArray.push(
<ReworkStation key={index} title={index + 1} status='' />,
);
data.map((it, idx) => {
const f2Date = it.f2_time.substr(0, 10);
const f2Hour = it.f2_time.substr(11, 8);
const f2DateFormatted = `${f2Date.substr(8, 2)}/${f2Date.substr(5, 2)}/${f2Date.substr(0, 4)}`;
const color = selection_color(it.color_d);
return (
stationArray.push(item.rework_name === it.rework_name && <ReworkTitle key={idx} vin={it.vin} date={f2DateFormatted} ipsq={it.defects} hour={f2Hour} color={color} />)
);
});
});
console.log(stationArray);
this.setState({
fillingStations: stationArray,
});
});
});
}
render() {
return (
<div className='row'>
{ this.state.fillingStations }
</div>
);
}
}
I don't know how to insert the children inside the parent already render.
I already solved, first render all the parent divs and after replace the position array with array.splice
render() {
const array = [];
this.state.fillingStations.map((item, index) => (
array.push(<Parent key={index} title={index + 1} status='' />),
this.state.fillingChildren.map((it, ind) => {
if (item.name === it.name) {
parent.splice(index, 1,
<Parent {...this.props}}>
<Child {...this.props} />
</Parent >);
}
})
));
return (
<div className='row'>
{array}
</div>
);
}
}
I'm mapping an array, and displaying them as a button. When users clicks on button i'm storing index and displaying data depending on that index. But there is some strange behavior. When I click on first button it does not store index in state. Only after clicking on other buttons , it's starts saving , but wrong index. What could be the problem?
displayButtons() {
const { data } = this.state
let sortedButtons = data.map((items, idx) => {
return (
<Button
key={idx}
className="project-btn"
primary
onClick={() => this.setState({ index: idx })}
>
{items.title}
</Button>
)
})
return sortedButtons
}
displayData() {
const { data, index } = this.state
let sortedData = data[index].settings.map((item, id) => {
const { _init_ } = item.settings
return _init_.map((message, index) => {
const { message_content } = message
return message_content === undefined ? null : (
<div key={index}>
<div>
<div className="settings-message">{message_content}</div>
</div>
<div>yes</div>
</div>
)
})
})
return sortedData
}