React reports props."function" is not a function
P粉475315142
2023-09-04 10:38:59
<p>I'm creating my first online store and I'm running into a problem. I made fake API which contains product card data and when I get them using <code>axios.get</code> and add to state I get "props.addCardData is not a function".I must say, everything works fine until I add <code>axios.get</code> . Other functions I use the same way as the function <code>addCardData</code>: I mean, I used <code>mapDispatchToProps</code> and I used <code>props.addCardData</code> ; - I'm not using them in <code>axios.get</code> or other requests). I had no problem using any of the features before. </p>
<p>I plan to get the data via <code>axios.get</code> and call a function from the card container that will call the dispatch with the action creator as a parameter. </p>
<p>I also found "Cannot read property of undefined (read 'addCardData').</p>
<p>Below, I've indicated the portion of code affected by the issue (I've indicated which code applies to which elements)</p>
<p>This is the code in the Cards component (I didn't add the imports here, but ofc I have all the imports): </p>
<pre class="brush:php;toolbar:false;">const Cards = (props) => {
axios.get('https://mocki.io/v1/8cb0f160-92f7-4cf8-a6c1-f63690df514e')
.then(response => {
props.addCardData(response.data)
})
let cardsArray = Object.keys(props.cardsData).map(card => (
<OfferCard
key={card.id}
bg={props.cardsData[card].bg}
id={props.cardsData[card].tagId}
title={props.cardsData[card].title}
text={props.cardsData[card].text}
button={
<Container fluid>
<Row className={'row-cols-auto'}>
{props.cardsData[card].button.map(button => (
<CardsButton
key={button.id}
link={button.link}
type={button.type}
class={button.class}
name={button.name}
/>
))}
</Row>
</Container>
}
/>
))
return (
<Container fluid>
<img src={'./backgrounds/bestoffers.png'} alt={'BEST OFFERS'} className={'img-fluid imgTab'} />
<Row xs={1} md={2} id={'cards-row'} className={'border border-4 g-3'}>
{/*row-cols-* - set the cards width by setting amount of cards in row*/}
{cardsArray}
</Row>
</Container>
)
}
export default Cards</pre>
<p>This is the code in <code>CardsContainer</code>: </p>
<pre class="lang-js prettyprint-override"><code>const mapStateToProps = (state) => {
return {
cardsData: state.homePage.cardsData
}
}
const mapDispatchToProps = (dispatch) => {
return {
addCardData: (data) => {
dispatch(addCardsData(data))
}
}
}
const CardsContainer = connect(mapStateToProps, mapDispatchToProps)(Cards);
export default CardsContainer
</code></pre>
<p>This is the code in the reducer: </p>
<pre class="lang-js prettyprint-override"><code>...
homePageCardsData = 'HOMEPAGE-CARDS-DATA'
initialState = {...} - includes "cardsData: {}"
const homePageReducer = (state = initialState, action) => {
let stateCopy;
switch (action.type) {
case homePageCardsData: {
stateCopy = {...state, cardsData: action.data}
break
}
...
default: return state;
}
return stateCopy;
...... - some functions here (not necessary to know)
}
export const addCardsData = (data) => ({
type: homePageCardsData,
data: data
})
</code></pre>
<p>When I try something like: </p>
<pre class="lang-js prettyprint-override"><code>const addCard = props.addCardData
axios.get('https://mocki.io/v1/8cb0f160-92f7-4cf8-a6c1-f63690df514e')
.then(response => {
addCard(response.data)
})
</code></pre>
<p>I'm getting lag on localhost (on the homepage!!), everything starts rendering slowly, and 70% of the time, the card block doesn't render. In other cases it can render after some time (rare chance). On the AdminPanel page, I'm rendering <code>Cards</code> because I need to see the changes while testing the menu, I get "TypeError: addCard is not a function."</p>
<p>If I remove this code from the component - everything works fine. </p>
<p>I must also say that I used the "debugger" and placed it in <code>homePageCardsData</code>. The script stops on the debugger (after <code>StateCopy</code> and before <code>break</code>). This means the script is correct, <code>dispatch</code> works and I can get into the case <code>homePageCardsData</code>. </p>
The problem is in the
Cards
component, which makes an Axios GET request as an unintentional side effect directly in the component's function body. This will most likely create a render loop, or at least make a GET request every timeCards
is rendered.Move this code into the
useEffect
hook so that it is called after the component is installed.Example:
You are using fairly old Redux code and we generally no longer use the
connect
higher-order component since theuseDispatch
anduseSelector
hooks replaced it usage. The current standard is to use theRedux-Toolkit
, which does reduce the amount of boilerplate you need to write.The following are examples of update suggestions:
reducer code, operation type, operation creator... all replaced by a single state slice.