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')
}