无法访问 JavaScript 对象中的属性

问题描述 投票:0回答:2

我是 javascript 的新手,我正在做一个项目,我需要访问 JavaScript 对象中的 prices 属性。此对象是条带集成中的产品对象。当我记录 productData.prices 时,它显示未定义,即使 productData 对象具有 prices 属性。我不确定为什么会这样。有人可以帮助我了解可能导致此问题的原因吗?

这是javascript代码

export default function Subscription() {
  const [loading, setLoading] = useState(false);
  const [products, setProducts] = useState([]);
  const { currentUser } = useAuth();
  const [stripe, setStripe] = useState(null);

  useEffect(() => {
    const initializeStripe = async () => {
      const stripe = await loadStripe(
        process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY
      );
      setStripe(stripe);
    };

    initializeStripe();

    const q = query(collection(db, "products"), where("active", "==", true));
    getDocs(q).then((querySnapshot) => {
      const products = {};
      querySnapshot.forEach(async (doc) => {
        products[doc.id] = doc.data();
        const priceSnapshot = await getDocs(
          collection(db, "products", doc.id, "prices")
        );
        priceSnapshot.forEach((price) => {
          products[doc.id].prices = {
            priceId: price.id,
            priceData: price.data(),
          };
        });
      });
      setProducts(products);
    });
  }, []);

  async function loadCheckOut(priceId) {
    setLoading(true);
    const usersRef = doc(collection(db, "users"), currentUser.uid);
    const checkoutSessionRef = collection(usersRef, "checkout_sessions");

    const docRef = await addDoc(checkoutSessionRef, {
      price: priceId,
      trial_from_plan: false,
      success_url: window.location.origin,
      cancel_url: window.location.origin,
    });

    onSnapshot(docRef, (snap) => {
      const { error, sessionId } = snap.data();
      if (error) {
        alert(`An error occurred: ${error.message}`);
      }

      if (sessionId && stripe) {
        stripe.redirectToCheckout({ sessionId });
      }
    });
  }

  return (
    <>
      <Container className="mt-4 mb-4">
        <h1 className="text-center mt-4">Choose Your Plan</h1>
        <Row className="justify-content-center mt-4">
          {Object.entries(products).map(([productId, productData]) => {
            console.log(productData);
            console.log(productData.prices);

            return (
              <Col md={4} key={productId}>
                <Card>
                  <Card.Header className="text-center">
                    <h5>{productData.name}</h5>
                    <h5>$20.00 / month</h5>
                  </Card.Header>
                  <Card.Body>
                    <h6>{productData.description}</h6>
                    <Button
                      onClick={() => loadCheckOut(productData?.prices?.priceId)}
                      variant="primary"
                      block
                      disabled={loading}
                    >
                      {loading ? (
                        <>
                          <Spinner
                            animation="border"
                            size="sm"
                            className="mr-2"
                          />
                          Loading...
                        </>
                      ) : (
                        "Subscribe"
                      )}
                    </Button>
                  </Card.Body>
                </Card>
              </Col>
            );
          })}
        </Row>
      </Container>
    </>
  );
}

console.log(productData);
记录以下对象

{
    "images": [],
    "description": "Access to dashboard",
    "tax_code": null,
    "active": true,
    "role": "premium",
    "name": "Premium",
    "metadata": {
        "firebaseRole": "premium"
    },
    "prices": {
        "priceId": "price_1N7SdbJHqW6OBlJ5itJgsGON",
        "priceData": {
            "billing_scheme": "per_unit",
            "interval": "month",
            "unit_amount": 2000,
            "currency": "usd",
            "product": "prod_NtF7pDBsqj5psh",
            "transform_quantity": null,
            "type": "recurring",
            "active": true,
            "metadata": {},
            "tax_behavior": "unspecified",
            "tiers": null,
            "tiers_mode": null,
            "interval_count": 1,
            "recurring": {
                "interval": "month",
                "aggregate_usage": null,
                "usage_type": "licensed",
                "interval_count": 1,
                "trial_period_days": null
            },
            "description": null,
            "trial_period_days": null
        }
    }
}

console.log(productData.prices);
日志未定义。有人可以帮助我了解这里发生的事情以及我如何解决它吗?谢谢。

javascript reactjs json stripe-payments
2个回答
0
投票

根据您提供的代码,问题似乎出在您设置

products
状态的方式上。在您的代码中,您将
products
初始化为一个空对象,然后遍历
querySnapshot
以使用
forEach
getDocs
异步填充它。

由于

products
的填充是异步完成的,因此有可能在异步操作完成之前设置状态。因此,当您尝试在代码的渲染部分访问
productData.prices
时,它可能仍然是未定义的。

要解决此问题,您可以修改代码以使用

Promise.all
在设置状态之前等待所有异步操作完成。这是实现此方法的代码的更新版本:

useEffect(() => {
  const initializeStripe = async () => {
    const stripe = await loadStripe(
      process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY
    );
    setStripe(stripe);
  };

  initializeStripe();

  const fetchData = async () => {
    const q = query(collection(db, "products"), where("active", "==", true));
    const querySnapshot = await getDocs(q);

    const products = {};

    const pricePromises = querySnapshot.docs.map(async (doc) => {
      const priceSnapshot = await getDocs(
        collection(db, "products", doc.id, "prices")
      );
      const prices = {};
      priceSnapshot.forEach((price) => {
        prices[price.id] = price.data();
      });
      return { id: doc.id, data: doc.data(), prices };
    });

    const productsData = await Promise.all(pricePromises);

    productsData.forEach((productData) => {
      products[productData.id] = { ...productData.data, prices: productData.prices };
    });

    setProducts(products);
  };

  fetchData();
}, []);

通过使用

Promise.all
map
创建一个承诺数组(
pricePromises
),我们可以确保在设置
products
的状态之前完成所有获取价格的异步操作。然后,在
productsData
数组中,每个
productData
对象包含相应的
prices
属性。

有了这个更新的代码,

productData.prices
在组件的渲染部分访问时不应再未定义。


0
投票

根据您提供的代码 💁🏻u200d♂️ 我认为,

products
对象在控制台中的显示方式 👀:

{"key":"value"}

👨🏻u200d🏫这里的密钥以实际字符串的形式呈现,🤸🏻u200d♂️以另一种方式,

products
obj 在控制台中像
JSON
数据一样格式化,所以当你想访问它时像
products.property
它不会工作,除非你从
{"key":"value"}
解析到
{key:"value"}
使用:

JSON.parse(products);

它将把它转换成一个具有可访问属性的实际javascript对象✨👌🏻。 或者你可以使用💁🏻u200d♂️:

products["property"]

它应该工作,希望,👀

© www.soinside.com 2019 - 2024. All rights reserved.