简体   繁体   English

当我使用“useCallback”时,出现 TypeError 错误

[英]when I use "useCallback " I get a TypeError error

I have const experience that creates 6 experiences with there popover.我有 const 经验,可以在弹出窗口中创建 6 次体验。 I am supposed to add useCallback to it but when I go I get and error.我应该向它添加 useCallback ,但是当我去的时候我得到了错误。

This is my component experience这是我的组件体验

import React, { memo, useCallback, useState } from 'react';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import Typography from '@material-ui/core/Typography';
import clsx from 'clsx';
import Button from '@material-ui/core/Button';
import Popover from '@material-ui/core/Popover';
import gastronomia from 'assets/experiences/gastronomia.jpg';
import productos from 'assets/experiences/productos.jpg';
import giftcard from 'assets/experiences/giftcard.jpg';
import diversion from 'assets/experiences/diversion.jpg';
import deporte from 'assets/experiences/deporte.jpg';
import belleza from 'assets/experiences/belleza.jpg';
import gastronomiaExperiences from 'data/gastronomia';
import productosExperiences from 'data/productos';
import giftcardExperiences from 'data/giftcard';
import diversionExperiences from 'data/diversion';
import deporteExperiences from 'data/deporte';
import bellezaExperiences from 'data/belleza';

// Proptypes definitions to the component.
const propTypes = {
  /** Custom root className. */
  className: PropTypes.string,
};

// Default props definitions.
const defaultProps = {
  className: null,
};

// Component's styles
const useStyles = makeStyles(theme => ({
  root: {
    display: 'block',
    margin: '0 auto',
    maxWidth: '50%',
    [theme.breakpoints.down('md')]: {
      maxWidth: '70%',
    },
    [theme.breakpoints.down('sm')]: {
      maxWidth: '100%',
    },
    '& .experiences-column': {
      display: 'inline-block',
      verticalAlign: 'top',
      textAlign: 'center',
      '&.col1': {
        width: '36.31%',
        [theme.breakpoints.down('sm')]: {
          width: 'initial',
        },
      },
      '&.col2': {
        width: '63.69%',
        [theme.breakpoints.down('sm')]: {
          width: 'initial',
        },
      },
      '& .experience': {
        padding: 2,
        position: 'relative',
        '& img': {
          width: '100%',
          display: 'block',
        },
        '& .experience-title': {
          position: 'absolute',
          bottom: 30,
          left: 0,
          right: 0,
          textAlign: 'center',
        },
      },
    },
  },
  paper: {
    width: '50%',
    left: '25% !important',
    height: '280px',
    '& img': {
      width: '100px',
      padding: '0 10px 0 10px',
    },
  },
  gastronomia: {
    backgroundColor: 'rgba(0,185,208,0.9)',
  },
  giftcard: {
    backgroundColor: 'rgba(221,165,174,0.9)',
  },
  deporte: {
    backgroundColor: 'rgba(189,143,205,0.9)',
  },
  productos: {
    backgroundColor: 'rgba(221,165,174,0.9)',
  },
  diversion: {
    backgroundColor: 'rgba(255,176,10,0.9)',
  },
  belleza: {
    backgroundColor: 'rgba(229,166,187,0.9)',
  },
  '@media screen and (max-width: 1024px)': {
    paper: {
      width: '70%', 
      left: '15% !important',
    },
  },
  '@media screen and (max-width: 480px)': {
   paper: {
    width: '100%',  
    left: '0% !important',  
    height: '350px',
  },
},
}), { name: 'ExperiencesStyle' });

     */const Experiences = memo(
  (props) => {
    const { className } = props;
    const classes = useStyles(props);

    const [anchorEl, setAnchorEl] = useState(null);

    const handleClick = (event) => {
      setAnchorEl(anchorEl ? null : event.currentTarget);
    };

    const handleClose = () => {
      setAnchorEl(null);
    };

    // const open = Boolean(anchorEl);

    const experience = useCallback((img, title, id, popoverCategory, anchorEl, classes, handleClick) => (
      <div
        className="experience"
        aria-describedby={id}
        id={id}
        onClick={handleClick}
        onKeyDown={handleClick}
        role="button"
        tabIndex="0"
      >
        <img
          data-sizes="auto"
          className="lazyload"
          data-src={img}
          alt={title}
        />
        <div className="experience-title">
          <Typography
            color="textSecondary"
            variant="subtitle2"
            className="highlight highlight1"
            display="inline"
          >
            { title }
          </Typography>
        </div>

        <Popover
          id={id}
          open={anchorEl && anchorEl.id === id}
          anchorEl={anchorEl}
          onClose={handleClose}
          classes={{paper: clsx(classes.paper, classes[id])}}
        >
          <div>
            <Button onClickAway={handleClose}>x</Button>
            <div>
              {
              popoverCategory.map(url => (

                <img
                  key={url}
                  data-sizes="auto"
                  className="lazyload"
                  src={url}
                  alt={title}
                />
              ))
            }
            </div>
          </div>
        </Popover>
      </div>
    ), []);

    return (
      <div className={clsx(classes.root, className)}>
        <div className="experiences-column col1">
          {experience(gastronomia, 'GASTRONOMÍA', 'gastronomia', gastronomiaExperiences)}
          {experience(giftcard, 'GIFT CARD', 'giftcard', giftcardExperiences)}
          {experience(deporte, 'DEPORTE', 'deporte', deporteExperiences)}
        </div>
        <div className="experiences-column col2">
          {experience(productos, 'PRODUCTOS', 'productos', productosExperiences)}
          {experience(diversion, 'DIVERSIÓN', 'diversion', diversionExperiences)}
          {experience(belleza, 'BELLEZA', 'belleza', bellezaExperiences)}
        </div>
      </div>
    );
  },
);

and the error is:错误是:

TypeError: Cannot read property 'paper' of undefined类型错误:无法读取未定义的属性“纸”

referring to this line参考这一行

classes={{paper: clsx(classes.paper, classes[id])}}

where I add the classes to the paper class of the popover.我将这些类添加到 popover 的纸类中。

I am not used to useCallback and new to react so I am lost.我不习惯 useCallback 和 new 来反应所以我迷路了。

const experience = useCallback((img, title, id, popoverCategory, anchorEl, classes, handleClick) => ( const 体验 = useCallback((img, title, id, popoverCategory, anchorEl, classes, handleClick) => (

The function you have created expects 7 things to be passed into it.您创建的函数需要传递 7 项内容。 But when you use it, you only pass in 4:但是当你使用它时,你只传入4个:

experience(gastronomia, 'GASTRONOMÍA', 'gastronomia', gastronomiaExperiences)经验(美食,'GASTRONOMÍA','美食',美食体验)

So the remaining 3 are all undefined inside the function.所以剩下的3个在函数内都是未定义的。 the anchorEl, classes, and handleClick variables defined at the top of your component are not visible inside experience, because those variable are being "shadowed".在组件顶部定义的 anchorEl、classes 和 handleClick 变量在体验中不可见,因为这些变量被“遮蔽”了。

So you could stop shadowing the variables by simply removing the last 3 arguments from your function definition:因此,您可以通过简单地从函数定义中删除最后 3 个参数来停止隐藏变量:

const experience = useCallback((img, title, id, popoverCategory) => (

However, i do have to express that useCallback doesn't seem to be doing anything for you.但是,我必须表示 useCallback 似乎没有为您做任何事情。 The benefit of useCallback is that you can have the experience variable be the same reference from one render to the next, but that doesn't seem to be a feature that you need. useCallback 的好处是您可以让experience变量成为从一个渲染到下一个渲染的相同引用,但这似乎不是您需要的功能。 Your component never tries to compare references of experience , nor is experience passed to any other component where it might be checked in a shouldComponentUpdate or React.memo.您的组件从来没有试图比较的参考experience ,也不是experience传递给它可能会在shouldComponentUpdate或React.memo检查任何其他组件。

So i would recommend deleting the useCallback entirely:所以我建议完全删除 useCallback :

const experience = (image, title, id, popoverCategory) => (

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM