React component error message using filter method - reactjs

Why am I getting a Type Error: Cannot read properties of undefined (reading 'filter') with the following React component? (I can console.log "squads" and "weekNo" and get the correct results)
import React from "react";
const Weekly = ({ squads, weekNo }) => {
return (
<>
<div>
{squads
.filter((squad) => squad.division === "NFC North")
.map((filteredDivision) => (
<li>{filteredDivision}</li>
))}
</div>
<div>
<p>{weekNo}</p>
</div>
</>
);
};
export default Weekly;

I'll add some comments to your code.
{squads
// 1
.filter((squad) => squad.division === "NFC North")
// 2
.map((filteredDivision) => (
<li>{filteredDivision}</li>
))}
Assuming squads is an array like below,
[{ division: 'a' }, { division: 'b' }]
After your statement 1, it gets all element with division set to "NFC North".
Now at your statement 2, remember it's still an array of objects. You can't print out an object directly. But you can print out one property of an object.
.map((squad) => (
<li>{squad.division}</li>
))
Hope this makes sense now.
NOTE: filter or map produces a new array.
Make sure the squads is valid at the first place. For example.
const Weekly = ({ squads, weekNo }) => {
if (!squads) return null
return (...)

Related

How to add items to a cart in React

I made an app with React which is displaying 9 products on the screen. I made a button to add them to a cart and I want to make the app functionally just for demo purpose. I used hooks and I don't know what I did wrong.Here are the errors that I'm receiving:
Uncaught TypeError: Cannot read properties of undefined (reading 'map')
at Products (Products.js:8:1)
react-dom.development.js:18523 The above error occurred in the <Products> component:
at Products (http://localhost:3000/main.f01d7322f0afd7419d5f.hot-update.js:30:5)
at Routes (http://localhost:3000/static/js/bundle.js:40456:5)
at Router (http://localhost:3000/static/js/bundle.js:40389:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:39198:5)
at App (http://localhost:3000/static/js/bundle.js:44:84)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
Here is the full project: https://github.com/burNN11/Project
import productItems from './data/Data'
const Products = ({handleAddProduct, productItems}) => {
console.log(productItems)
return (
<div className='produse'>
{productItems.map((item)=> (
<div className='produs' key={item.id}>
<div>
<img className='imagine-produs'
src={item.image}
alt = {item.name}
Edit
I cloned your project, applied my fix and got it to work. The offending code is in App.js, in the handleAddProduct() handler:
const handleAddProduct = product => {
const ProductExist = cartItems.find(item => item.id === product.id);
if (ProductExist) {
setCartItems(
cartItems.map(item =>
item.id === product.id
? { ...ProductExist, quantity: ProductExist.quantity + 1 }
: item
)
);
} else {
setCartItems([...cartItems, {
...product,
quantity: ProductExist.quantity + 1 // <-- error is here
}]);
}
};
In the else block, ProductExist is undefined, as the only way to get into the else block is for it to be undefined. But you try to use ProductExist.quantity + 1. It should be just 1, like this:
const handleAddProduct = product => {
const ProductExist = cartItems.find(item => item.id === product.id);
if (ProductExist) {
setCartItems(
cartItems.map(item =>
item.id === product.id
? { ...ProductExist, quantity: ProductExist.quantity + 1 }
: item
)
);
} else {
setCartItems([...cartItems, {
...product,
quantity: 1 // <-- Change here
}]);
}
};
With this change, the cart feature is working on my machine, on localhost. There is no UI update to show the new items in the cart, but I checked the console and the items are being added correctly, without errors.
Hope this helped.
Original answer
In components/Products.js, you define the <Products/> component as:
import productItems from './data/Data'
const Products = ({handleAddProduct, productItems}) => {
console.log(productItems)
...
You override the productItems import by defining it as a prop. This is because of how JavaScript handles scope. The definition in the function parameters takes precedence.
You should change the lines above to remove the prop, like this:
import productItems from './data/Data'
const Products = ({handleAddProduct}) => {
console.log(productItems)
...
You don't pass the productItems prop in App.js, hence the prop is undefined when you try to map over it.

how to render array in object in array? (react)

const checked = [{
food:['apple', 'banana']
drink:['wine', 'beer']
}];
render (
<>
{checked.map((value) => {
value.food.forEach((each) => (
<div>{each}</div>
)
)}
</>
)
I tried this way and noting is shown in browser..
what would be the best way to approach?
Need to Return Your data like below!!
import React from "react";
export default function App() {
let checked = [{
food:['apple', 'banana'],
drink:['wine', 'beer']
}];
return (
<div className="App">
{
checked.map((item) => {
return item.food.map((fruit)=>{
return <h1>{fruit}</h1>
})
})
}
</div>
);
}
Your code has multiple errors.
It should be render instead of rander
While defining object, multiple properties should be separated using a comma. So put comma after the food array.
forEach doesn't return any thing. It just iterates over an array. So, if you want to return something (in this case a div element), use map.
Also, you should use key for each div element otherwise react would give you a warning in the console. This is done so that while re-rendering, based on the keys, react would understand which component to re-render and which to skip. Otherwise all the div would be re-rendered which is a costly operation.
const checked = [
{
food: ["apple", "banana"],
drink: ["wine", "beer"]
}
]
return (
<>
{checked.map((value) => {
return value.food.map((each, index) => {
return <div key={index}>{each}</div>;
});
})}
</>
);
There is a couple of improvements that require to be implemented to make the list displayed.
First, the map method does not return anything.
Two solutions:
Remove the curly brackets checked.map((value) => value...
Add a return keyword: checked.map((value) => { return value...}
The other issue is that the second loop is iterated using the forEach method.
The difference between the two (forEach and map) from MDN:
The forEach() method executes a provided function once for each array
element.
MDN
The map() method creates a new array populated with the results of
calling a provided function on every element in the calling array.
MDN
Basically, it means that forEach does not return anything and that why you need to use map
checked.map((value) => {
return value.food.map((each) => (<div>{each}</div>))
})}
or
checked.map((value) =>
value.food.map((each) => (<div>{each}</div>))
)}
You are iterating over the checked array items using forEach which won't induce any results since the forEach method
executes a provided function once for each array element.
which won't result in a transformed array.
What you are looking for is the map method which
creates a new array populated with the results of calling a provided function on every element in the calling array.
hence returning your transformed items so that they can be rendered (transformed at compilation time to ReactElement using the JSX syntax).
Note that you need to use an HTML tag instead of a React.Fragment the empty tag <> syntax:
const checked = [{
food:['apple', 'banana'], // there is a missing comma here
drink:['wine', 'beer']
}];
render ( // render and not rander
<div> // div instead of empty tag
{checked.map((item) => item.food.map((each) => <div>{each}</div>))}
</div>
)
Can check this approach. if you want to print just food values, below code should work. If you want to print all the values (both food and drink), then uncomment the commented code below.
export default function App() {
const checked = [
{
food: ["apple", "banana"],
drink: ["wine", "beer"]
},
{
food: ["grapes", "oranges"],
drink: ["coke", "sprite"]
}
];
// to display values of all arrays.
// return (
// <>
// {checked.map((value) => {
// const keys = Object.keys(value);
// return keys.map((eachKey) => {
// return value[eachKey].map((individualValue) =>
// (
// <div>{individualValue}</div>
// )
// )
// });
// })
// }
// </>
// );
// To display just food values.
return (
<>
{checked.map((value) => {
return value.food.map((each) => <div>{each}</div>);
})}
</>
);
}

Attempting to map within React returning undefined

I have the following Mongoose schema:
const SubmitDebtSchema = new Schema ({
firebaseId: String,
balance: [{
balanceDate: Date,
newBalance: Number
}]
});
This database schema is called in my parent component using the useEffect hook, and passed down as props to my child component.
const fetchDebts = debts.map (debt => {
return (
<IndividualDebtCard key={debt._id}
transactions={debt} />
)
})
I then store the prop in my child component as a variable, and use another useEffect to console the result of this variable upon rendering:
const debts = props.transactions
useEffect(() => {
console.log(debts)
}, [debts])
For reference, this is what an example console log would look like:
balance: Array (2)
0 {_id: "5fea07cd143fd50008ae1ab2", newBalance: 1500, balanceDate: "2020-12-28T16:29:00.391Z"}
1 {_id: "5fea0837b2a0530009f3886f", newBalance: 1115, balanceDate: "2020-12-28T16:30:45.217Z"}
What I then want to do, is map through this variable, pick out each 'newBalance', and 'balanceDate' and render them on my page.
However, I'm getting an undefined error every time I try to load my component...
This is what I've tried so far:
{ debts.map(debt => {
return (
<div className="transaction-history">
<div className="transaction-history-entry">
<p>{debt.balance.balanceDate}</p>
<p>-£{debt.balance.newBalance}</p>
</div>
</div>
)
})}
Can anyone point out where I'm going wrong? I know it'll be something obvious, but can't figure it out.
EDIT: I think the undefined is coming from how I'm attempting to call my 'balanceDate' and 'newBalance' - if I console log what I'm trying to map it's returning undefined.
You need to check for debts to have value. try this:
{
debts.balance && !!debts.balance.length && debts.balance.map((debt, index) => {
return (
<div key={index} className="transaction-history">
<div className="transaction-history-entry">
<p>{debt.balance.balanceDate}</p>
<p>-£{debt.balance.newBalance}</p>
</div>
</div>
);
});
}

can not set data from back end use React.js

This is from back-end data format:
{data: Array(15)}
data[0]:
option: Array(1)
0: "String"
_id: "String"
col1: "String"
col2: "String"
col3: "String"
....data[14]
and this is front end code:
const Component1 = () => {
const [dbvalue, setDbvalue] = useState(null)
//option, _id, col1, col2, col3
const getAlldbValue = async () => {
try {
const resp = await services.getAlldbValue();
console.log(resp) //enter F12 can get total data from back end.
setDbvalue(resp.data.data)
console.log(dbvalue) //setDbvalue() not work , this print null
} catch (error) {
console.log(error)
alert('Failed!')
}
}
useEffect(() => {
getAlldbValue()
}, [])
if(!dbvalue) {
return (
<p>Loading Component...</p> //not appear
)
}
return (
<p>{dbvalue}</p> //not appear
);
};
export default Component1;
How can I set this nested object json into this dbvalue?
I want use dbvalue.keyname to display.
Thanks for your help
To display JavaScript objects in your jsx you can do the following:
<pre>{JSON.stringify(dbvalue,undefined,2)}</pre>
If your data[x].option is an object where every property is a string then you can do the following to list them:
const ListProps = props => (
<ul>
{Object.entries(props).map(([key, value]) => (
<li key={key}>{value}</li>
))}
</ul>
)
//here is how you would render listProps
<listProps {...data[0].option} />
First, your console.log is printing null because when you use setState, the variable you just setted will only be setted in the next render. Try printing resp.data.data instead and then put console.log(dbvalue) outside the getAlldbValue function, so you can understand better.
Also,
`return (
<p>{dbvalue}</p> //not appear
);`
your trying to put an object into a HTML Element, try dbvalue[0].col1 or whatever you want to show instead.
Hope it helps you.

Why do I get Type Error when passing props in map?

I can't seem to pass the 'name' prop to the component without a type error. I have an array of objects being passed in as {reslist} and each object in that array has a logo, and name value. I cant seem to pass name or logo into my return.
import React from 'react';
import './Resources.css'
import CodeCard from '../CodeCard/CodeCard.js'
const Resources = ({ reslist }) => {
return (
<div>
<h3 className='resCall'>Check out my Code!</h3>
<div className='resCards'>
{ reslist.map((i) => {
return ( <CodeCard
key={i}
name={reslist[i].name}
/>
);
})
}
</div>
</div>
)
}
export default Resources;
Here is the error
TypeError: Cannot read property 'name' of undefined (anonymous
function)
Here is my Resource List
const ResList = [
{
logo: 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png',
name:'GitHub'
},
{
logo: 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png',
name:'GitHub'
},
{
logo: 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png',
name:'GitHub'
},
{
logo: 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png',
name:'GitHub'
},
]
export default ResList
Your map callback has incorrect parameters. The first parameter is value, 2nd is index (ref):
reslist.map((value, index) => {
return (<CodeCard
key={index}
name={reslist[index].name}
/>)
})
But of course, you can use value directly too:
reslist.map((value, index) => {
return (<CodeCard
key={index}
name={value.name}
/>)
})
I'm assuming reslist is an array of objects. When you call .map on an array of objects, the first parameter (in your example, i) is each object. The second parameter is the index. I think you're getting these two mixed up.
reslist.map((item, i) => (
<CodeCard
key={i}
name={item.name}
/>
))
Importing components don't need to have .js:
edit it with import { CodeCard } from '../CodeCard'
ps: please don't shot me

Resources