I have an App component where I define two functions A and B.
I am then passing these two functions to a Card component as follow
<Card
key = {el.key}
item={el}
onPress={{
select : ()=>A(el.key),
discard : ()=>B(el.key)
}}
/>
however, for some reason, when inside my Card i do something like
....
<div
className={className}
onClick={props.onPress.select}>
</div>
...
I get this nasty error
react-dom.development.js:18687 The above error occurred in the <Card> component:
at Card (http://localhost:5174/src/components/Card.jsx?t=1670102247232:33:48)
at div
at div
at div
at App (http://localhost:5174/src/App.jsx?t=1670102247232:24:31)
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.
react-dom.development.js:26923 Uncaught TypeError: Cannot read properties of undefined (reading 'select')
at Card (Card.jsx:28:32)
at renderWithHooks (react-dom.development.js:16305:18)
at mountIndeterminateComponent (react-dom.development.js:20074:13)
at beginWork (react-dom.development.js:21587:16)
at beginWork$1 (react-dom.development.js:27426:14)
at performUnitOfWork (react-dom.development.js:26557:12)
at workLoopSync (react-dom.development.js:26466:5)
at renderRootSync (react-dom.development.js:26434:7)
at recoverFromConcurrentError (react-dom.development.js:25850:20)
at performConcurrentWorkOnRoot (react-dom.development.js:25750:22)
what am I doing wrong?
Here below both the App code and the Card code
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import Card from './components/Card'
import data from "./assets/data.json"
import {nanoid} from "nanoid"
function App() {
const [people, setPeople] = useState(data['people'].map(
el=>{
return {
...el,
'key' : nanoid(),
}
}
))
const [myCard, setMyCard] = useState(
{
"name":"Name and Surname",
"img":"https://i.picsum.photos/id/1070/200/300.jpg?hmac=dJNTYlLwT_0RupxbJNbw5Wj-q2cCTB4Xh-GqWRofIIc",
"description": "This is a silly descriptionhis is a silly descriptionhis is a silly description",
'key' : nanoid(),
"selected":false,
"active":true,
}
)
function SelectCard(CardKey){
console.log('SelectCard')
setPeople(oldPeople=>{
return oldPeople.map(el=>{
return el.key === CardKey
? { ...el, 'state': el.state === 'active'?'selected': 'active'}
: { ...el, 'state':'active'}
})
})
}
function DiscardCard(CardKey){
console.log('DiscardCard')
setPeople(oldPeople=>{
return oldPeople.map(el=>{
return el.key === CardKey
? { ...el, 'state': el.state === 'discarded'?'active': 'discarded'}
: { ...el}
})
})
}
const cards = people.map(el=>{
return <Card
key = {el.key}
item={el}
onPress={{
select : ()=>SelectCard(el.key),
discard : ()=>DiscardCard(el.key)
}}
/>
})
return (
<div className="App">
<div className='container'>
<div className='left'>
<div className='cards'>
{cards}
</div>
</div>
<div className = 'right'>
<h4>You are: </h4>
<Card key = {myCard.key} item={myCard}/>
</div>
</div>
</div>
)
}
export default App
and the card
import { useState } from 'react'
function Card(props) {
//const [count, setCount] = useState(0)
function getClassName(state) {
switch (state) {
case "active":
return "";
case "selected":
return "overlay-selected";
case "discarded":
return "overlay-discarded";
case "complete":
return "overlay-complete";
default:
return "";
}
}
const className = `card ${getClassName(props.item.state)}`
return (
<div
className={className}
onClick={props.onPress.select}>
<img className='card-img' alt='Card Image' src={props.item.img} />
<h3 className='card-title'>{props.item.name} </h3>
{ props.item.state === 'selected' ?
<div className='card-cta'>
<button
className='btn btn-back'
onClick={ props.item.selected ? (event)=>
{
props.onPress.select
//event.stopPropagation()
}
: ()=>{}}
>Back</button>
<button
className='btn btn-discard'
onClick={
(event) =>{
//event.stopPropagation()
props.onPress.discard
console.log('called me')
}
}
>Discard</button>
</div>
:
<p className='card-description'>{props.item.description} </p>
}
</div>
)
}
export default Card
CodePudding user response:
This happens for the
<h4>You are: </h4>
<Card key={myCard.key} item={myCard} />
where you do not pass any onPress property.
So you need to either pass dummy methods for this case as well, or use the optional chaining operator ?., like so props.onPress?.select
Additionally, you should actually call the methods from your buttons
so
(event) =>{
//event.stopPropagation()
props.onPress.discard
console.log('called me')
}
should become
(event) =>{
//event.stopPropagation()
props.onPress.discard() // <-- added the () here
console.log('called me')
}
