Populating the list with array of items - javascript

I have an array of items, and I have accessed one of the item's property to divide the items into two separate arrays. But when I try to populate the created array in the component of the DOM, gives an error
Uncaught Error: Objects are not valid as a React child (found: object with keys {text, key, completedItem}). If you meant to render a collection of children, use an array instead.
The code is as follows:
render() {
let { items } = this.props;
let listItems = items.map( (item) => {
return (
<TodoItem text={item.text}
key={item.key}
ID={item.key}
isComplete={item.completedItem}
onDelete={this.props.onDelete}
onEdit={this.props.onEdit}
handleComplete={this.props.handleComplete} />
);
});
const revArray = listItems.reverse();
console.log("Reversed Array : ", revArray);
const completedItems = items.filter((item) => {
return ( item.completedItem == true );
});
console.log("Items Completed Array : ", completedItems);
const filterCompleted = items.filter((item) => {
return ( item.completedItem == false );
});
console.log("Items not Completed Array : ", completedItems);
const resultArrItems = [ ...filterCompleted, ...completedItems];
console.log("Final Array : ", resultArrItems);
return (
<div className="card card-body mt-5">
<ul className="list-group my-3">
<h3 className="text-capitalize text-center"> todo list </h3>
<div>{resultArrItems}</div>
</ul>
</div>
);
}
I get the resultArrItems as of the exact order I need the array elements to be, when I view the array in the console, but the problem is I can't populate the component in the DOM with the resultArrItems. The error that I get is mentioned above. Is there any solution for this ...? and also what is the reason for this behavior ...?

You only can represent elements in render or return with JSX syntax. Currently you are trying to display an array - resultArrItems. You need to use .map() and return inside a valid JSX element for each iteration.
You can try the following:
return <div className="card card-body mt-5">
<ul className="list-group my-3">
<h3 className="text-capitalize text-center"> todo list </h3>
<div>
{
resultArrItems.map((e, i) => <div key={i}>
{i} {/* here you can access also each elements properties */}
</div>)
}
</div>
</ul>
</div>
I hope this helps!

Related

ReactJS not able to print nested values in rest api response

This is first time I am writing a React app and have create a sample app using create-react-app. I am calling a rest api using axios and it returns me json below which is nested. My component display the first level attributes but not nested one please help understand what I am doing wrong.
<Card type="inner" title="Social">
{social.dataall.map((social1,i) => (
<div key={i} class="card">
<div class="card-body">
<h5 class="card-title">Name: {social1.FullName}</h5>
{social1.Member1.map(function (member11, j) {
return <div key={j}> <h5>member11</h5></div>
{member11.User2.map(function (usr2, k) {
return <div key={k}> <h5>Type: {usr2.firstName}</h5></div>
})}
})}
</div>
</div>
))}
</Card>
JSON to parse and display:
{"app":{"dataall":[{"FullName":"Payment","DisplayName":"Payment","Id":"3366d5e59","Member1":[{"User2":[{"userId":"331322934","firstName":"fName1","lastName":"lName1"}],"Role3":[{"roleName":"Business"}]},{"User2":[{"userId":"331322934","firstName":"fName","lastName":"lName"}],"Role3":[{"roleName":"Owner"}]}]}]}}
Output:
Name: Payment
member11
member11
Not able to print the value for Type: {usr2.firstName}
You are closing the <div> element here:
return <div key={j}> <h5>member11</h5></div>
// ^^^^^^
That means the following code ({member11.User2...) is not part of the JSX element. It simply follows the return statement. Code after a returns statement is not executed:
(function() {
console.log("shown");
return;
console.log("not shown");
}());
You didn't explain how you want the UI to be structured but a simple solution would be to move the mapping inside the <div> element.
<div class="card-body">
<h5 class="card-title">Name: {social1.FullName}</h5>
{
social1.Member1.map(function (member11, j) {
return (
<div key={j}>
<h5>member11</h5>
{
member11.User2.map(function (usr2, k) {
return <div key={k}> <h5>Type: {usr2.firstName}</h5></div>
})
}
</div>
);
})
}
</div>

How to iterate through an array inside an array.map function?

I am trying to iterate an array inside another loop in my react app. I have a json file that contains data that looks like this:
[
{
"id":"0001",
"photos":[
"IMG_9239.JPG",
"2019-01-07.jpg",
"IMG_9261.JPG"
]
},
{
"id":"0002",
"photos":[
"IMG_9239.JPG",
"2019-01-07.jpg",
"IMG_9261.JPG"
]
},
{
"id":"0003",
"photos":[
"IMG_9239.JPG",
"2019-01-07.jpg",
"IMG_9261.JPG"
]
}
]
And this is my react component:
const ListItems = ({data}) => {
return (
<div id="items-container">
{data.map( item => (
<p>{item.id}</p>
//iterate the [photos] array in an img tag
//<img src ="photo" />
))}
</div>
)
}
I am trying {item.photos.map....} but it seems like it's not a valid syntax. Can you please help?
Multiple JSX elements require a parent, or at least a psuedo-parent. Here, you can use a fragment <> as the parent of what gets returned from the .map callback, enclosing both the <p> and the <img>s:
const ListItems = ({data}) => {
return (
<div id="items-container">
{data.map( item => (
<>
<p>{item.id}</p>
{item.photos.map(({ src }) => <img src={src}></img>}
</>
))}
</div>
)
}

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

In My react component,
My UI loads perfectly but there is console error which i wanted to fix error says - 'Each child in a list should have a unique "key" prop' for below code.
Guide me how I can pass keys to detailsContent
render() {
const header = (
<div className={css.deviceDetailsBody}>
<div className="sidebar__header">
<div className="sidebar__title">
<div>
{hostname}
{this._renderCloser()}
<div className={"sidebar__subtitle"}>
<div className="toolsBar">
<div className="toolsBarlet">
<div className="toolsItemNarrow">{deviceTypeView}</div>
{complianceStatusView}
<div className="toolsItemNarrow">{managementIpAddress}</div>
{deviceUpTime}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
const horizontalLine = <div className="sidebar__horiz_line" />;
const body = (
<div className="body">
{tabs}
{tools}
</div>
);
const detailsContent = [header, horizontalLine, body].map(
currentComponent => currentComponent
);
return (
<div>
{sideBarShow && (
<Sidebar {...sidebarProps}>
<div>{detailsContent}</div>
</Sidebar>
)}
</div>
);
}
Added the header, body code for more clarity.
Each child in a list should have a unique "key" prop
If using Components and not plain jsx elements, simply add a key prop to the currentComponent jsx. Note for simplicity I just used index as key.
const detailsContent = [header, horizontalLine, body].map(
(CurrentComponent, index) => (<CurrentComponent key={index} />)
);
See CodeSandbox
Using elements, please refer to the accepted answer.
You can use React.cloneElement to add keys
const detailsContent = [header, line, body].map(
(element, index) => React.cloneElement(element, {key: index})
);

Curly braces inside curly braces in React

I have presentational component in React. And with products.some i am trying to check if any item inside products is checked. And if some item is checked, render parent block for RequestedProduct component. I know that the problem is a second pair of curly braces as React think it's a prop. Is there another way to do this?
const Requested = ({ products, getCurrentTime }) => (
<div className="pepper-pin-body-tab requested-tab">
<div className="pepper-pin-body-tab-title">
Запрошенные
</div>
<div className="pepper-pin-body-tab-indicator" />
{products.some(product => product.checked) ? (
<div className="requested-tab-list-requested">
<div className="requested-tab-list-requested-time">
{getCurrentTime()}
</div>
{products.filter((product, key) => {
if (product.checked) {
return (
<RequestedProduct
key={key}
title={product.title}
/>
);
}
})}
</div>
) : null}
</div>
);
Issue is, filter will not return the custom element/value, it will always return the array element for which you return true from filter body.
Solution is, use only map or combination of filter and map.
Using map:
{
products.map((product, key) => product.checked ?
<RequestedProduct key={key} title={product.title} />
: null
}
Using combination of filter and map:
{
products
.filter(product => product.checked)
.map((product, key) => <RequestedProduct key={key} title={product.title}/>)
}
Check this snippet, you will get a better idea:
const arr = [
{a: 1},
{a: 2},
{a: 3},
{a: 4}
];
const afterFilter = arr.filter((el,i) => {
if(i%2) {
return `Hello world ${i}`;
}
});
// it will print the array items, not the Hello World string
console.log('afterFilter', afterFilter);
I'd recomment splitting the code a bit, which makes it intent a lot clearer. You'll end up with the following (for example), which should not be triggering errors.
The main problem is in the unintended side effects of the filter, whereas you most likely want to use a filter and a map. That makes the intent to another developer much clearer.
const contents = (products, getCurrentTime) => (
const filtered = products.filter(product => product.checked);
<div className="requested-tab-list-requested">
<div className="requested-tab-list-requested-time">
{getCurrentTime()}
</div>
{filtered.map((product, key) => <RequestedProduct key={key} title={product.title}/>)}
</div>
);
const Requested = ({products, getCurrentTime}) => {
const isAnythingChecked = products.some(product => product.checked);
return <div className="pepper-pin-body-tab requested-tab">
<div className="pepper-pin-body-tab-title">
Запрошенные
</div>
<div className="pepper-pin-body-tab-indicator"/>
{isAnythingChecked ? contents(products, getCurrentTime) : null}
</div>
};

React - how to map nested object values?

I am just trying to map nested values inside of a state object. The data structure looks like so:
I want to map each milestone name and then all tasks inside of that milestone. Right now I am trying to do so with nested map functions but I am not sure if I can do this.
The render method looks like so:
render() {
return(
<div>
{Object.keys(this.state.dataGoal).map( key => {
return <div key={key}>>
<header className="header">
<h1>{this.state.dataGoal[key].name}</h1>
</header>
<Wave />
<main className="content">
<p>{this.state.dataGoal[key].description}</p>
{Object.keys(this.state.dataGoal[key].milestones).map( (milestone, innerIndex) => {
return <div key={milestone}>
{milestone}
<p>Index: {innerIndex}</p>
</div>
})}
</main>
</div>
})}
</div>
);
}
I think that I could somehow achieve that result by passing the inner index to this line of code: {Object.keys(this.state.dataGoal[key].milestones) so it would look like: {Object.keys(this.state.dataGoal[key].milestones[innerIndex]).
But I am not sure how to pass the innerIndex up. I have also tried to get the milestone name by {milestone.name} but that doesn't work either. I guess that's because I have to specify the key.
Does anybody have an idea? Or should I map the whole object in a totally different way?
Glad for any help,
Jakub
You can use nested maps to map over the milestones and then the tasks array:
render() {
return (
<div>
{Object.keys(this.state.dataGoal.milestones).map((milestone) => {
return (
<div>
{this.state.dataGoal.milestones[milestone].tasks.map((task, idx) => {
return (
//whatever you wish to do with the task item
)
})}
</div>
)
})}
</div>
)
}
What you want is flatMap. flatMap takes an array and a function that will be applied to each element in the array, which you can use to (for example) access properties inside each object in the array. It then returns a new array with the returned values from its lambda:
function flatMap(arr, lambda) {
return Array.prototype.concat.apply([], arr.map(lambda))
}
In our case, we don't have an array, we have an object so we can't use flatMap directly. We can convert the object to an array of its properties' values with Object.values and then make a function that accesses the object with the passed key:
function tasksFromDataGoal(key) {
return flatMap(Object.values(dataGoal[key].milestones), milestone => milestone.tasks)
}
Working example:
function flatMap(arr, lambda) {
return Array.prototype.concat.apply([], arr.map(lambda))
}
function tasksFromDataGoal(key) {
return flatMap(Object.values(dataGoal[key].milestones), milestone => milestone.tasks)
}
const dataGoal = { 123: { milestones: { milestone1: { tasks: ['a', 'b'] }, milestone2: { tasks: ['c', 'd'] } } } }
alert(tasksFromDataGoal('123'))
Author of this implementation of flatMap: https://gist.github.com/samgiles/762ee337dff48623e729
Managed to refactor the render method:
render() {
return(
<div>
{Object.keys(this.state.dataGoal).map( (key, index) => {
const newDataGoal = this.state.dataGoal[key].milestones;
return <div key={key}>
<header className="header">
<h1>{this.state.dataGoal[key].name}</h1>
</header>
<Wave />
<main className="content">
<p>{this.state.dataGoal[key].description}</p><br /><br />
{Object.keys(this.state.dataGoal[key].milestones).map( (milestoneKey) => {
const milestonesData = this.state.dataGoal[key].milestones[milestoneKey];
return <div className="milestone-wrap" key={milestoneKey}>
<label className="milestone-label">{milestonesData.name}</label>
{Object.keys(milestonesData.tasks).map( (taskKey) => {
return <div className="task clearfix" key={taskKey}>
<input
className="checkbox-rounded"
name="task"
type="checkbox"
checked={milestonesData.tasks[taskKey].done}
onChange={(e) => this.handleInputChange(e, key, taskKey)} />
<div className="task-content">
<p className="task-name">{milestonesData.tasks[taskKey].name}</p>
<p className="task-date">{milestonesData.tasks[taskKey].finishDate}</p>
</div>
</div>
})}
</div>
})}
</main>
</div>
})}
</div>
);
}

Categories

Resources