Using map on array of objects results in a errormessage - javascript

I am trying to figure out why this simple code does not work, it feels like I have done exactly the same thing many times before without errors. What have I done wrong?
import React, {useState} from 'react'
import { MenuItem } from '../menu-item/menu-item.component'
import './directory.styles.scss'
export const Directory = () => {
const sections = [
{
title: 'hats',
imageUrl: 'https://i.ibb.co/cvpntL1/hats.png',
id: 1,
linkUrl: 'shop/hats'
},
{
title: 'jackets',
imageUrl: 'https://i.ibb.co/px2tCc3/jackets.png',
id: 2,
linkUrl: 'shop/jackets'
},
{
title: 'sneakers',
imageUrl: 'https://i.ibb.co/0jqHpnp/sneakers.png',
id: 3,
linkUrl: 'shop/sneakers'
},
{
title: 'womens',
imageUrl: 'https://i.ibb.co/GCCdy8t/womens.png',
size: 'large',
id: 4,
linkUrl: 'shop/womens'
},
{
title: 'mens',
imageUrl: 'https://i.ibb.co/R70vBrQ/men.png',
size: 'large',
id: 5,
linkUrl: 'shop/mens'
}
];
return (
<div className="directory-menu">
{sections.map((title, imageUrl, id) => <MenuItem key={id} title={title} imageUrl={imageUrl}/>)}
</div>
)
}
Error Message:
Error: Objects are not valid as a React child (found: object with keys
{title, imageUrl, id, linkUrl}). If you meant to render a collection
of children, use an array instead.

You are not destructuring properly i.e.
.((title, imageUrl, id) =>
should be
.(({title, imageUrl, id}) =>

Check out this post, it's a common React error.
You could also try something like this
Object.entries(sections).map((x)=>
return x.title;
})

Related

react Material-table unable to change each icon set color? [duplicate]

This question already has answers here:
How can I change the color of material-table icons of onRowAdd, onRowUpdate, onRowDelete?
(2 answers)
Closed 1 year ago.
I am using the material-table library and trying to change each icon color. Would you please help me to do so? I tried custom CSS but it's changing all icon color at once not the specific one?
here is my code sandbox link.
In short: I want to change color of each of three icons add, edit, delete
Here is my code I am using a material-table library with material-ui. Also is it possible to change these default icons?
List.js
import React, { useState } from 'react';
import './App.css';
import MaterialTable from 'material-table'
import makeStyles from "#material-ui/core/styles/makeStyles";
const useStyles = makeStyles(theme => ({
rootTable: {
'& .MuiIconButton-colorInherit' : {
color: '#6a2cd8'
},
'& .MuiIconButton-root .MuiIconButton-colorInherit': {
color: 'red'
},
width: theme.spacing(150)
}
}));
const empList = [
{ id: 1, name: "Neeraj", email: 'neeraj#gmail.com', phone: 9876543210, city: "Bangalore" },
{ id: 2, name: "Raj", email: 'raj#gmail.com', phone: 9812345678, city: "Chennai" },
{ id: 3, name: "David", email: 'david342#gmail.com', phone: 7896536289, city: "Jaipur" },
{ id: 4, name: "Vikas", email: 'vikas75#gmail.com', phone: 9087654321, city: "Hyderabad" },
]
function App() {
const [data, setData] = useState(empList)
const columns = [
{ title: "ID", field: "id", editable: false },
{ title: "Name", field: "name" },
{ title: "Email", field: "email" },
{ title: "Phone Number", field: 'phone', },
{ title: "City", field: "city", }
]
const classes = useStyles();
return (
<div className="App">
<h1 align="center">React-App</h1>
<h4 align='center'>Material Table with CRUD operation</h4>
<div className={classes.rootTable}>
<MaterialTable
title="Employee Data"
data={data}
columns={columns}
editable={{
onRowAdd: (newRow) => new Promise((resolve, reject) => {
const updatedRows = [...data, { id: Math.floor(Math.random() * 100), ...newRow }]
setTimeout(() => {
setData(updatedRows)
resolve()
}, 2000)
}),
onRowDelete: selectedRow => new Promise((resolve, reject) => {
const index = selectedRow.tableData.id;
const updatedRows = [...data]
updatedRows.splice(index, 1)
setTimeout(() => {
setData(updatedRows)
resolve()
}, 2000)
}),
onRowUpdate:(updatedRow,oldRow)=>new Promise((resolve,reject)=>{
const index=oldRow.tableData.id;
const updatedRows=[...data]
updatedRows[index]=updatedRow
setTimeout(() => {
setData(updatedRows)
resolve()
}, 2000)
})
}}
options={{
actionsColumnIndex: -1, addRowPosition: "first"
}}
/>
</div>
</div>
);
}
export default App;
You can import icons you wish to change their color from #material-ui/icons, change the color you want, and pass them as icons prop to MaterialTable: codesandbox.
import { Edit } from "#material-ui/icons";
...
icons={{
Edit: React.forwardRef((props, ref) => (
<Edit style={{ color: "green" }} {...props} ref={ref} />
))
}}

unable to destructuring two objects simultaneously

How can I map movies by using columns as a property reference.
Like
{movies.map(item => {columns.map(column => item.column.path)})}
but using this i'm getting result as undefined
Movies contains all details about movies
const movies = [
{
_id: "5b21ca3eeb7f6fbccd471815",
title: "Terminator",
genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
numberInStock: 6,
dailyRentalRate: 2.5,
publishDate: "2018-01-03T19:04:28.809Z",
liked: true,
},
{
_id: "5b21ca3eeb7f6fbccd471816",
title: "Die Hard",
genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
numberInStock: 5,
dailyRentalRate: 2.5,
},
{
_id: "5b21ca3eeb7f6fbccd471817",
title: "Get Out",
genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
numberInStock: 8,
dailyRentalRate: 3.5,
},
{
_id: "5b21ca3eeb7f6fbccd471819",
title: "Trip to Italy",
genre: { _id: "5b21ca3eeb7f6fbccd471814", name: "Comedy" },
numberInStock: 7,
dailyRentalRate: 3.5,
},
{
_id: "5b21ca3eeb7f6fbccd47181a",
title: "Airplane",
genre: { _id: "5b21ca3eeb7f6fbccd471814", name: "Comedy" },
numberInStock: 7,
dailyRentalRate: 3.5,
}];
Columns contains all properties that are needed to access the movies
const columns = [
{ path: "title", label: "Title" },
{ path: "genre", label: "Genre" },
{ path: "numberInStock", label: "Stock" },
{ path: "dailyRentalRate", label: "Rate" }];
I know this problem can be solved using 2 loops.
1 outer loop for movies after getting each movie, use a 2nd internal loop to access the properties
Update: After getting #rory-mccrossan answer
Further, how can I map this data in a table such that
This is the code part regarding the same that I used.
import React, { Component } from "react";
import _ from "lodash";
class TableBody extends Component {
renderCell = (item, column) => {
if (column.content) return column.content(item);
return _.get(item, column.path);
};
createKey = (item, column) => {
return item._id + (column.path || column.key);
};
render() {
const { data, columns } = this.props;
return (
<tbody>
{data.map((item) => (
<tr key={item._id}>
{columns.map((column) => (
<td key={this.createKey(item, column)}>
{this.renderCell(item, column)}
</td>
))}
</tr>
))}
</tbody>
);
}
}
export default TableBody;
But I'm getting the 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.)
The main issue is that how can I map data in a table
There's two issues here. Firstly the braces around the second map() call will be interpreted as a code block, yet it does not return any value so the resulting array will be empty. Remove those braces.
Secondly, item.column.path needs to be item[column.path] as you're using column.path as the property accessor of item.
Here's a working example:
const movies = [{_id:"5b21ca3eeb7f6fbccd471815",title:"Terminator",genre:{_id:"5b21ca3eeb7f6fbccd471818",name:"Action"},numberInStock:6,dailyRentalRate:2.5,publishDate:"2018-01-03T19:04:28.809Z",liked:!0},{_id:"5b21ca3eeb7f6fbccd471816",title:"Die Hard",genre:{_id:"5b21ca3eeb7f6fbccd471818",name:"Action"},numberInStock:5,dailyRentalRate:2.5},{_id:"5b21ca3eeb7f6fbccd471817",title:"Get Out",genre:{_id:"5b21ca3eeb7f6fbccd471820",name:"Thriller"},numberInStock:8,dailyRentalRate:3.5},{_id:"5b21ca3eeb7f6fbccd471819",title:"Trip to Italy",genre:{_id:"5b21ca3eeb7f6fbccd471814",name:"Comedy"},numberInStock:7,dailyRentalRate:3.5},{_id:"5b21ca3eeb7f6fbccd47181a",title:"Airplane",genre:{_id:"5b21ca3eeb7f6fbccd471814",name:"Comedy"},numberInStock:7,dailyRentalRate:3.5}];
const columns = [{path:"title",label:"Title"},{path:"genre",label:"Genre"},{path:"numberInStock",label:"Stock"},{path:"dailyRentalRate",label:"Rate"}];
let output = movies.map(item => columns.map(column => item[column.path]));
console.log(output);

Map object with array in javascript

I'm using Vue Select Image for multi selecting images. Vue Select Image expects the array to be with the following keys
[{
id: '1',
src: 'https://unsplash.it/200?random',
alt: 'Alt Image 1'
}, {
id: '2',
src: 'https://unsplash.it/200?random',
alt: 'Alt Image 2'
}]
And my api route gives the object with following keys:
(2)[{…}, {…}]
0:
created_at: "2019-07-26 07:44:56"
id: 3
name: null
path: "img/d1ef5a9c54ee32df12c213b1491e1636.jpg"
thumb: "img/thumb_d1ef5a9c54ee32df12c213b1491e1636.jpg"
updated_at: "2019-07-26 07:44:56"
Below is my code snippet:
import VueSelectImage from "vue-select-image";
import "vue-select-image/dist/vue-select-image.css";
export default {
data() {
return {
dataImages: [{
id: "",
src: "",
alt: ""
}]
},
selected: {},
initialLoad() {
axios.get("api/gallery").then(response => {
this.dataImages = Object.keys(response.data.data).map(function(key) {
return [Number(key), response.data.data[key]];
});
// console.log(response.data.data);
});
},
components: {
VueSelectImage
},
};
<template>
<div>
<vue-select-image :dataImages="dataImages" #onselectimage="selected"></vue-select-image>
</div>
</template>
The above code maps object with array with its own keys. And displays 2 circle as there are 2 data receiving from api. Clicking on them gives the following error:
Error in event handler for "onselectimage": "TypeError: fns.apply is not a function"
Map through array of objects you get from API, it returns new array with objects with desired fields.
axios.get("api/gallery").then(response => {
this.dataImages = response.data.data.map((obj, index) => {
return {
id: obj.id,
src: obj.path,
alt: `Alt image ${index}`
};
});
});

problem with infinite loop in function hook useEffect

I have a problem with an infinite loop on my hook,
I'm passing the data of the local JSON breakfast. If you are iterating with map the data and I am taking it to paint a menu of buttons.
If I remove the data at the end of the function, and leave the empty array, it sends me the following error:
const BreakfastComponent = () => {
const breakfast = [
{
id: 0,
name: "Sandwich de jamón y queso",
price: '35',
img: "https://i.ibb.co/ynC9xHZ/sandjc.png",
},
{
id: 1,
name: "Jugo Natural",
price: '15',
img: "https://i.ibb.co/8mrd4MK/orangejuice.png",
},
{
id: 2,
name: "Café americano",
price: '20',
img: "https://i.ibb.co/nsj1GL0/americancoffe.png",
},
{
id: 3,
name: "Café con leche",
price: '28',
img: "https://i.ibb.co/GRPBm7j/coffeandmilk.png",
}
];
const [stateProduct, setStateProduct] = useState([ ]);
useEffect(() => {
setStateProduct(breakfast);
}, [breakfast]);
return (
<section className="databreakfast">
{stateProduct.map((element, item) =>
<ButtonsBComponent
key={item}
{...element}
/>
)}
</section>
)
};
export default BreakfastComponent;
React Hook useEffect has a missing dependency: 'breakfast'. Either include it or remove the dependency array react-hooks/exhaustive-deps
The problem is simple, you have breakfast array as a dependency to useEffect and in useEffect you are setting the breakfast array itself. Now since the const breakfast array is declared inside the component, a new reference to it is generated everytime and since useEffect sets the array in state, it re-renders and on next re-render the comparison for breakfast array fails since the reference has changed.
The solution is simple, you don't need to have the const array in the component and also you don't need to use useEffect
const breakfast = [
{
id: 0,
name: "Sandwich de jamón y queso",
price: '35',
img: "https://i.ibb.co/ynC9xHZ/sandjc.png",
},
{
id: 1,
name: "Jugo Natural",
price: '15',
img: "https://i.ibb.co/8mrd4MK/orangejuice.png",
},
{
id: 2,
name: "Café americano",
price: '20',
img: "https://i.ibb.co/nsj1GL0/americancoffe.png",
},
{
id: 3,
name: "Café con leche",
price: '28',
img: "https://i.ibb.co/GRPBm7j/coffeandmilk.png",
}
];
const BreakfastComponent = () => {
const [stateProduct, setStateProduct] = useState(breakfast);
return (
<section className="databreakfast">
{stateProduct.map((element, item) =>
<ButtonsBComponent
key={item}
{...element}
/>
)}
</section>
)
};
export default BreakfastComponent;
useEffect's second argument is an array of state/hooks to be watched and when they change, to run the effect. Since your breakfast is a const, I'm guessing you just want the original stateProduct to be breakfast. So instead of using [] as the default, use breakfast.
const [stateProduct, setStateProduct] = useState(breakfast);
Also, probably a good idea to declare const breakfast ... outside of your react functional component so it doesn't re-declare it on every re-render.

return array of objects from props React JS

so I have the following component that is a dropdown list created using react-select.
import React from 'react'
import Select from 'react-select';
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
];
class MealsFilters extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedOption: null,
};
}
handleChange = (selectedOption) => {
this.setState({ selectedOption });
console.log(`Option selected:`, selectedOption);
}
render() {
const { selectedOption } = this.state;
return (
<div className="container my-3">
<div className="row">
<div className="col-lg-4 col-md-6 col-sm-8">
<Select
isMulti
isSearchable
placeholder={"catégories"}
value={selectedOption}
onChange={this.handleChange}
options={options}
/>
</div>
</div>
</div>
)
}
}
export default MealsFilters;
the options variable is the default one from the docs. I actually need to replace its values by each meal category available.
To do so, as you can see, I need to create an array of objects with a value and a label.
this component accesses meal categories through props called meals that are like so:
console.log(this.props.meals);
=> [{
id: 0,
name: spaghettis,
category: italian,
price: 5.99},
{
id: 1,
name: hamburger,
category: american,
price: 7.99},
{
etc.
}, {}]
How can I take advantage of this.props.meals to get my options array of objects ?
EDIT: multiple meals can have the same category, and I need each category to only appear once in the options.
Map over your this.props.meals array, and create the needed options array,
<Select
isMulti
isSearchable
placeholder={"catégories"}
value={selectedOption}
onChange={this.handleChange}
options={this.props.meal.map(item=>({value: item.id, label: item.name}))}
/>
You could do something like this:
options={this.props.meals.map(
({id, name})=>({value:id,label:name})
)}
You could also use redux connect to create a container that will map the data to dropdown values for you
You can merge the data by category in the following way:
var items = [
{
id: 0,
name: 'spaghettis',
category: 'italian',
price: 5.99,
},
{
id: 1,
name: 'hamburger',
category: 'american',
price: 7.99,
},
{
id: 2,
name: 'other hamburger',
category: 'american',
price: 7.99,
},
];
console.log(
[
...items.reduce(
(result, item) => (
result.get(item.category)
? result.get(item.category).push(item.id)
: result.set(item.category, [item.id]),
result
),
new Map(),
),
].map(([label, value]) => ({ label, value })),
);
In the component it'll look like this:
options={[
...this.props.meals.reduce(
(result, item) => (
result.get(item.category)
? result.get(item.category).push(item.id)
: result.set(item.category, [item.id]),
result
),
new Map(),
),
].map(([label, value]) => ({ label, value }))}
You only need the "name" property so when you map through meals, simply retrieve it. Then upper case the first letter.
const meals = [{
id: 0,
name: "spaghettis",
category: "italian",
price: 5.99
},
{
id: 1,
name: "hamburger",
category: "american",
price: 7.99
}
]
const result = meals.map(({name}) => ({
label: `${name[0].toUpperCase()}${name.slice(1)}`,
value: name
}))
console.log(result);
You can use getOptionLabel and getOptionValue props.
<Select
options={this.props.meals},
getOptionLabel={m => m.name}
getOptionValue={m => m.id} />
https://react-select.com/props
getOptionLabel generic = (option) => string
Resolves option data to a string to be displayed as the label by components
getOptionValue generic = (option) => string
Resolves option data to a string to compare options and specify value attributes

Categories

Resources