You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React类组件handleAddProduct调用find方法出现未定义错误求助

React类组件购物车添加逻辑错误排查与修复

错误原因分析

  • 状态访问错误:类组件中cartItems存储在this.state中,直接访问this.cartItems会得到undefined,调用find方法自然触发类型错误。
  • 点击事件绑定错误:onClick={this.handleAddProduct(value)}会在组件渲染时立即执行函数,而非点击时触发,同时无法正确传递参数。
  • 缺少唯一标识:产品数据data中的对象没有id字段,导致无法通过item.id === value.id判断产品是否已存在于购物车。

修复步骤

  1. 正确访问状态:所有涉及cartItems的操作都从this.state.cartItems获取,而非直接访问this.cartItems。
  2. 修正点击事件:使用箭头函数包裹点击回调,确保点击时才执行函数并传递正确参数:onClick={() => this.handleAddProduct(value)}。
  3. 添加产品唯一id:在data数组的产品对象中添加id字段,作为唯一标识。
  4. 优化状态更新:使用setState的函数式更新,确保每次更新都基于最新的状态值,避免状态滞后问题。

完整修正代码

import React, { Component } from 'react'
import '../Pages.css'
import { Box, Card, CardContent, Typography, CardMedia, Button} from "@mui/material";
import Grid from '@mui/material/Grid';
import styled from "styled-components";
import WaveSurfer from 'wavesurfer.js';
import ye from '../ye.mp3';
import yepic from '../Musicbox/yepic.jpg'

const data = [
  {
    id: 1, // 添加唯一id
    songImg: ye,
    songName: "Burna Boy - Ye",
    songGenre: "Afrobeat",
    songDetails: "125 BPM,  3:45mins",
    songPrice: "N4300",
  },
]

const WaveformContainer = styled.div`
display: block;  
align-items: center;
justify-content: center;
height: 100px;  width: 100%;
background: transparent;
`;

const Wave = styled.div`
width: 50%;
height: 90px;
`;

const PlayButton = styled.button`
  display: flex;
  justify-content: center;
  align-items: center;
  width: 60px;
  height: 60px;
  background: #EFEFEF;
  border-radius: 50%;
  border: none;
  outline: none;
  cursor: pointer;
  padding-bottom: 3px;
  &:hover {
    background: #DDD;
  }
`;

class Boxthree extends Component {
  constructor(props){
    super(props);
    // 合并状态到constructor,避免重复定义state
    this.state = {
      playing: false,
      cartItems: []
    };
  }

  componentDidMount() {
    const trackthree = document.querySelector('#trackthree');

    this.wavethree = WaveSurfer.create({
      barWidth: 1,
      cursorWidth: 1,
      container: '#wavethree',
      backend: 'WebAudio',
      height: 40,
      progressColor: 'blue',
      responsive: true,
      waveColor: '#EFEFEF',
      cursorColor: 'transparent',
      fillParent: false,
      minPxPerSec: 15, 
    });

    this.wavethree.load(trackthree);
  };

  handlePlay = () => {
    this.setState({ playing: !this.state.playing });
    this.wavethree.playPause();
  };

  handleAddProduct = (value) => {
    // 从state中获取cartItems
    const valueExist = this.state.cartItems.find((item) => item.id === value.id);

    if(valueExist){
      // 使用函数式更新确保拿到最新state
      this.setState(prevState => ({
        cartItems: prevState.cartItems.map((item) => 
          item.id === value.id ? 
          {...item, quantity: item.quantity + 1}: item
        )
      }));
    } else {
      this.setState(prevState => ({
        cartItems: [...prevState.cartItems, {...value, quantity: 1}]
      }));
    }
  }

  render() {
    return (
      <div className='NewContainer'>
        {data.map((value,index) => {
          return(
            <Grid container key={index}> {/* 添加key到外层Grid */}
              <Grid item md={4} >
                <div className='cardbox'>
                  <Card sx={{display: 'block', }}> 
                    <Box sx={{padding: '10px', position: 'relative', }}>
                      <CardMedia square 
                        component='img'
                        height='200'
                        src= {yepic}   
                        alt='splash'/>
                      <WaveformContainer className='wavecon'> 
                        <PlayButton className='playbtn' onClick={this.handlePlay}> 
                          {!this.state.playing ? 'Play' : 'Pause'}
                        </PlayButton>
                        <Wave id="wavethree"/> 
                        <audio id="trackthree" src={ye}/>
                      </WaveformContainer>
                    </Box>
                    <CardContent>
                      <Typography>
                        {value.songName}
                      </Typography>
                      <Typography>
                        {value.songGenre}
                      </Typography>
                      <Typography>
                        {value.songDetails}
                      </Typography> 
                      <Box  sx={{ display: 'flex',justifyContent: 'space-between', }}>
                        <Typography>
                          Exclusive
                        </Typography>
                        <Typography>
                          Lease
                        </Typography>
                      </Box>
                      <Button variant='contained'
                        sx={{ bgcolor: '#3E0660', color: 'white', display: 'flex', borderRadius: '30px', }} 
                        onClick={() => this.handleAddProduct(value)} {/* 修正点击事件 */}
                      >
                        <Typography sx={{ paddingLeft: '5px',  paddingRight: '5px',  paddingTop: '3px', paddingBottom: '3px' , }}>Add To Cart</Typography>
                        <Box sx={{ bgcolor: 'white', color: 'black', borderRadius: '30px', paddingLeft: '5px',  paddingRight: '5px',  paddingTop: '4px', paddingBottom: '3px'  }}>
                          <Typography>{value.songPrice}</Typography>
                        </Box>
                      </Button>
                    </CardContent>
                  </Card>
                </div>
              </Grid>
            </Grid>
          )
        })}
      </div>
    );
  }
};

export default Boxthree;

额外优化说明

  • 把分散的state定义合并到constructor中,符合类组件的规范。
  • 在Grid container上添加key属性,避免React列表渲染警告。
  • 移除了冗余的setCartItems方法,直接在handleAddProduct中使用setState,简化逻辑。

内容的提问来源于stack exchange,提问作者Uche Chukwu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 20:27:20