【问题标题】:ReactJS - Unhandled Rejection (TypeError): Cannot read property 'id' of undefinedReactJS - 未处理的拒绝(TypeError):无法读取未定义的属性“id”
【发布时间】:2021-02-06 21:45:13
【问题描述】:

基本上,我通过将其与 stripe 和 Commercejs 链接来创建一个电子商务测试站点。一切正常,直到结帐表格加载。我可以输入信息,但是,在加载页面时出现错误:

“未处理的拒绝(TypeError):无法读取未定义的属性'id'”仅一行代码。即:

setShippingOption(options[0].id);

该代码嵌套在:

const fetchShippingOptions = async (checkoutTokenId, country, stateProvince = null) => {
   const options = await commerce.checkout.getShippingOptions(checkoutTokenId, { country, region: stateProvince });

setShippingOptions(options);
setShippingOption(options[0].id);
};

这段代码本质上是地址形式,如下:

import React, { useState, useEffect } from 'react';
import { InputLabel, Select, MenuItem, Button, Grid, Typography } from '@material-ui/core';
import { useForm, FormProvider } from 'react-hook-form';
import { Link } from 'react-router-dom';

import { commerce } from '../../lib/commerce';
import FormInput from './FormInput';

const AddressForm = ({ checkoutToken, next }) => {
  const [shippingCountries, setShippingCountries] = useState([]);
  const [shippingCountry, setShippingCountry] = useState('');
  const [shippingSubdivisions, setShippingSubdivisions] = useState([]);
  const [shippingSubdivision, setShippingSubdivision] = useState('');
  const [shippingOptions, setShippingOptions] = useState([]);
  const [shippingOption, setShippingOption] = useState('');
  const methods = useForm();

  const fetchShippingCountries = async (checkoutTokenId) => {
    const { countries } = await commerce.services.localeListShippingCountries(checkoutTokenId);

    setShippingCountries(countries);
    setShippingCountry(Object.keys(countries)[0]);
  };

  const fetchSubdivisions = async (countryCode) => {
    const { subdivisions } = await commerce.services.localeListSubdivisions(countryCode);

    setShippingSubdivisions(subdivisions);
    setShippingSubdivision(Object.keys(subdivisions)[0]);
  };

  const fetchShippingOptions = async (checkoutTokenId, country, stateProvince = null) => {
    const options = await commerce.checkout.getShippingOptions(checkoutTokenId, { country, region: stateProvince });

    setShippingOptions(options);
    setShippingOption(options[0].id);
  };

  useEffect(() => {
    fetchShippingCountries(checkoutToken.id);
  }, []);

  useEffect(() => {
    if (shippingCountry) fetchSubdivisions(shippingCountry);
  }, [shippingCountry]);

  useEffect(() => {
    if (shippingSubdivision) fetchShippingOptions(checkoutToken.id, shippingCountry, shippingSubdivision);
  }, [shippingSubdivision]);

  return (
    <>
      <Typography variant="h6" gutterBottom>Shipping address</Typography>
      <FormProvider {...methods}>
        <form onSubmit={methods.handleSubmit((data) => next({ ...data, shippingCountry, shippingSubdivision, shippingOption }))}>
          <Grid container spacing={3}>
            <FormInput required name="firstName" label="First name" />
            <FormInput required name="lastName" label="Last name" />
            <FormInput required name="address1" label="Address line 1" />
            <FormInput required name="email" label="Email" />
            <FormInput required name="city" label="City" />
            <FormInput required name="zip" label="Zip / Postal code" />
            <Grid item xs={12} sm={6}>
              <InputLabel>Shipping Country</InputLabel>
              <Select value={shippingCountry} fullWidth onChange={(e) => setShippingCountry(e.target.value)}>
                {Object.entries(shippingCountries).map(([code, name]) => ({ id: code, label: name })).map((item) => (
                  <MenuItem key={item.id} value={item.id}>
                    {item.label}
                  </MenuItem>
                ))}
              </Select>
            </Grid>
            <Grid item xs={12} sm={6}>
              <InputLabel>Shipping Subdivision</InputLabel>
              <Select value={shippingSubdivision} fullWidth onChange={(e) => setShippingSubdivision(e.target.value)}>
                {Object.entries(shippingSubdivisions).map(([code, name]) => ({ id: code, label: name })).map((item) => (
                  <MenuItem key={item.id} value={item.id}>
                    {item.label}
                  </MenuItem>
                ))}
              </Select>
            </Grid>
            <Grid item xs={12} sm={6}>
              <InputLabel>Shipping Options</InputLabel>
              <Select value={shippingOption} fullWidth onChange={(e) => setShippingOption(e.target.value)}>
                {shippingOptions.map((sO) => ({ id: sO.id, label: `${sO.description} - (${sO.price.formatted_with_symbol})` })).map((item) => (
                  <MenuItem key={item.id} value={item.id}>
                    {item.label}
                  </MenuItem>
                ))}
              </Select>
            </Grid>
          </Grid>
          <br />
          <div style={{ display: 'flex', justifyContent: 'space-between' }}>
            <Button component={Link} variant="outlined" to="/cart">Back to Cart</Button>
            <Button type="submit" variant="contained" color="primary">Next</Button>
          </div>
        </form>
      </FormProvider>
    </>
  );
};
export default AddressForm;

除此之外,这是我收到的唯一错误。

顺便说一句,我对 JavaScript 还是很陌生,我刚上大学一年级。

【问题讨论】:

  • 您确定这些选项有 id 属性吗?
  • console.log(options) 放在setShippingOptions(options); 之前,看看它为控制台打印了什么。
  • 这样你就有了。 await commerce.checkout.getShippingOptions 返回一个空数组,而我假设它应该返回一个对象数组。
  • options[0] 未定义,因此没有可访问的 id 属性。您应该首先检查数组长度,或者使用可选链接运算符,即options[0]?.id
  • 我的意思是你可以先检查options[0] 是否存在,然后再访问该对象,例如options[0] &amp;&amp; options[0].id。 Optional Chaining 运算符允许您更简洁地编写此代码。没有像官方文档这样的东西??? :developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

标签: javascript reactjs e-commerce


【解决方案1】:

确保 Commercejs 配送设置中的国家/地区包含所有正确的区域。我使用的是美国,但注意到我只启用了 2 个区域。

【讨论】:

    【解决方案2】:

    在仪表板上检查运输设置,您可能会错过细分

    【讨论】:

      【解决方案3】:

      编辑美国区域并在添加/编辑国家/地区确保添加所有 57 个区域。

      【讨论】:

        【解决方案4】:

        刚刚遇到您的问题并解决了它。我也用了和你一样的资源。

        如果您在 fetchShippingOptions const 中使用 console.log(options),您可能会看到国内或国际的描述值。这些是您的运输类别。

        根据您的 CommerceJS 设置,默认选择其中之一。当它选择默认值时,它会尝试立即加载您的细分。​​

        问题是:如果您尝试渲染与后端不匹配的细分,它会认为该值未定义。因此,您必须转到 Commerce JS 配置文件中的运输选项,并确保您的帐户中每个运输选项的 所有 细分都可用(以便您的 API 密钥可以正确读取后端值)。

        您是否有忘记启用所有区域的运输条目?这就是我所拥有的。请记住,在您的表单中,您正在映射所有细分。这并不一定意味着,当您尝试使用 API 推送数据时,所有后端端点都已正确连接。

        因此,请转到您的 Commerce JS 帐户并检查此项目的运输选项。如果任何条目显示的区域少于应有的区域,则该条目没有正确容纳您的端点,最终将无法读取值。

        【讨论】:

          猜你喜欢
          • 2019-07-19
          • 2020-06-01
          • 2019-01-24
          • 2021-01-13
          • 2019-04-07
          • 1970-01-01
          • 2019-06-03
          • 2020-04-09
          • 2019-11-13
          相关资源
          最近更新 更多