开发者问题收集

未捕获的类型错误:无法读取未定义的属性(读取‘源’)

2021-09-21
14458

我尝试从 commerceJS API 访问从不同模块获取并作为 prop 传递的数据,只有当我调用嵌套产品对象时,代码才会中断,并出现此错误 Uncaught TypeError: Cannot read properties of undefined (reading 'source')

我在店面上使用了相同的 API, {product.media.source 运行正常。我正在尝试制作一个预览模块,当我调用嵌套对象时,它会中断。 请帮忙。

这是我的代码

const Preview = ({ products, onAddToCart }) => {
const [product, setProduct] = useState({});

const params = useParams();



const findProduct = (id) => {
    return products.find((product) => {
        setProduct(product);
        return product.id === id;
    });
};
const productId = params.id;

useEffect(() => {
    findProduct(productId);
});
return (
    <Card sx={{ maxWidth: 345 }} style={{ marginTop: '90px' }}>
        <CardMedia image={product.media.source} title={product.name}></CardMedia>
        <CardContent>
            <Typography gutterBottom variant='h5' component='div'>
                {product.name}
            </Typography>
            <Typography
                variant='body2'
                color='textSecondary'
                dangerouslySetInnerHTML={{ __html: product.description }}
            ></Typography>
        </CardContent>
        <CardActions>
            <IconButton component={Link} variant='outlined' to='/'>
                Go Back
            </IconButton>
            <IconButton aria-label='Add to Cart' onClick={() => onAddToCart(product.id, 1)}>
                <AddShoppingCart />
            </IconButton>
        </CardActions>
    </Card>
);

这是产品对象 产品对象

2个回答

显然,您的 product 对象默认不包含 media 字段。您需要等到它可用后才能使用它。

尝试以下方法:

const Preview = ({ products, onAddToCart }) => {
    const [product, setProduct] = useState();

    const params = useParams();

    console.log(products[0]);
    console.log(params.id);

    const findProduct = useCallback((id) => {
        return products.find((product) => {
            if (product.id === id) { // <-- render optimization
                setProduct(product);
                return true;    
            }
            return false;
        });
    }, [products]);

    const productId = useMemo(() => params.id, [params.id]);

    useEffect(() => {
        findProduct(productId);
    }, [productId, findProduct]);

    const renderCard = useCallback(() => {
        if (!product) return null; // <-- here you can implement your placeholder component
        return (
            <Card sx={{ maxWidth: 345 }} style={{ marginTop: '90px' }}>
                <CardMedia image={product.media.source} title={product.name}/>
                <CardContent>
                    <Typography gutterBottom variant='h5' component='div'>
                        {product.name}
                    </Typography>
                    <Typography
                        variant='body2'
                        color='textSecondary'
                        dangerouslySetInnerHTML={{ __html: product.description }}
                    ></Typography>
                </CardContent>
                <CardActions>
                    <IconButton component={Link} variant='outlined' to='/'>
                        Go Back
                    </IconButton>
                    <IconButton aria-label='Add to Cart' onClick={() => onAddToCart(product.id, 1)}>
                        <AddShoppingCart />
                    </IconButton>
                </CardActions>
            </Card>
        );
    }, [product]);

    return renderCard();
};

或者像这样:

const initialState = { // <-- you need to change this as you need
    active: true,
    assets: [/* ... */],
    categories: [/* ... */],
    checkout_url: {
        checkout: 'placeholder://checkout.url',
        display: 'placeholder://display.url',
        /* ... */
    },
    collects: {/*...*/}
    created: 0,
    description: 'placeholder description',
    extra_fields: [/* ... */],
    hsa: {/* ... */},
    id: 'placeholder_id',
    invenotry: {/* ... */},
    is: {/* ... */},
    media: {
        type: 'image',
        source: 'placeholder://image.source',
        /* ... */
    },
    meta: null,
    /* ... */
};

const Preview = ({ products, onAddToCart }) => {
    const [product, setProduct] = useState(initialState);

    const params = useParams();

    console.log(products[0]);
    console.log(params.id);

    const findProduct = useCallback((id) => {
        return products.find((product) => {
            if (product.id === id) { // <-- render optimization
                setProduct(product);
                return true;    
            }
            return false;
        });
    }, [products]);

    const productId = useMemo(() => params.id, [params.id]);

    useEffect(() => {
        findProduct(productId);
    }, [productId, findProduct]);

    return (
        <Card sx={{ maxWidth: 345 }} style={{ marginTop: '90px' }}>
            <CardMedia image={product.media.source} title={product.name}/>
            <CardContent>
                <Typography gutterBottom variant='h5' component='div'>
                    {product.name}
                </Typography>
                <Typography
                    variant='body2'
                    color='textSecondary'
                    dangerouslySetInnerHTML={{ __html: product.description }}
                ></Typography>
            </CardContent>
            <CardActions>
                <IconButton component={Link} variant='outlined' to='/'>
                    Go Back
                </IconButton>
                <IconButton aria-label='Add to Cart' onClick={() => onAddToCart(product.id, 1)}>
                    <AddShoppingCart />
                </IconButton>
            </CardActions>
        </Card>
    );
};
wowandy
2021-09-21

根据上面的代码

console.log(products[0]);
console.log(params.id);

const findProduct = (id) => {
    return products.find((product) => {
        setProduct(product);
        return product.id === id;
    });
};

看起来产品是一个数组而不是一个对象。我认为这是您可能错过的地方。

因此, product.media.source 会抛出错误,因为 product.media 未定义。

请检查您可能要添加的产品。

Omkar
2021-09-21