我正在學習 React 課程,每周都會遇到一些挑戰,這些挑戰導致我們創建電子商務。我的問題是,我有一個硬編碼的產品資料,當進入頁面 useEffect 創建一個承諾,使用 setTimeOut 在 2 秒內解決并回傳產品資料。
在之前的挑戰中,我已經做了基本相同的事情,只有一個包含多個產品的陣列并遵循以下設計模式:ItemListContainer請求資料,將資料傳遞給ItemList,將.map()應用于陣列和每個專案創建一個Item組件,通過 props 發送資料。
在當前的挑戰中,當我們使用單個產品時,我們不必在任何陣列上執行 .map() ,并且由于某種原因,這會導致 Item 組件(在本例中稱為ItemDetail)在資料到達之前呈現,盡管它只渲染不依賴于到達它的資料的部分。
演示:演示(它呈現樣式化的 div 和“$”符號)。
在查看代碼幾個小時后,我無法弄清楚它為什么會發生以及我可以做些什么來修復它。
Github 倉庫: enzom-uy/coderhouseECommerce
ItemDetailContainer 代碼:
import React, { useState, useEffect } from 'react'
import ItemDetail from '../ItemDetail/ItemDetail'
const productData = {
id: '4',
name: 'Cuarto producto',
description: 'Descripcion del cuarto producto',
price: 10,
pictureUrl:
'https://media.istockphoto.com/vectors/thumbnail-image-vector-graphic-vector-id1147544807?k=20&m=1147544807&s=612x612&w=0&h=pBhz1dkwsCMq37Udtp9sfxbjaMl27JUapoyYpQm0anc='
}
const ItemDetailContainer = () => {
const [detailedProduct, setDetailedProduct] = useState({})
useEffect(() => {
const fetchingData = new Promise((res, rej) => {
setTimeout(() => {
res(productData)
}, 2000)
})
fetchingData.then((res) => {
setDetailedProduct(res)
console.log('Se guardaron los datos')
})
fetchingData.catch((err) => {
console.log('Failed')
})
}, [])
return (
<>
<h1>Producto detallado</h1>
<ItemDetail product={detailedProduct} />
</>
)
}
export default ItemDetailContainer
專案詳細代碼:
import React from 'react'
export default function ItemDetail({ product }) {
return (
<div className="bg-slate-100 w-60 flex flex-col items-center mx-1 px-2 border border-slate-400 text-center">
<span>{product.name}</span>
<img src={product.pictureUrl} width="120" />
<p>{product.description}</p>
<span>${product.price}</span>
</div>
)
}
uj5u.com熱心網友回復:
簡短的回答
它顯示了樣式化的 div 和美元符號,因為這是您在 JSX 中包含的內容。要在資料到達之前將其洗掉,您可以根據存在的資料有條件地將其作為 return 陳述句的一部分。這可能看起來像這樣(使用我的答案后面列出的更簡單的選項)
return (
<>
<h1>Producto detallado</h1>
{detailedProduct.name && <ItemDetail product={detailedProduct} />}
</>
)
為什么會發生
如果您有一個不依賴資料的簡單組件,那么它將在 return 陳述句中呈現所有內容。在下面的示例中,即div、h1和p元素。
function Parent() {
return (
<div>
<h1>Hello!</h1>
<p>We have no products to sell.</p>
</div>
);
}
如果您有一個依賴資料的組件,例如來自 API(或 setTimeout),那么這不會改變。將呈現回傳陳述句中包含的內容(包括任何子組件)。
function Parent() {
const [data, setData] = useState({});
useEffect(() => {
fetch('https://api.com')
.then(res => res.json())
.then(setData)
.catch(err => console.error(err));
}, []);
return (
<div>
<h1>Hello!</h1>
<Child data={data} />
</div>
);
}
function Child({ data }) {
return (
<p>The name is: {data.name}</p>
);
}
在這種情況下,在從 API 回傳資料之前,<p>將出現帶有文本“名稱是:”的子元素元素,因為它是回傳的一部分。然后,當資料到達時,它會重新渲染并出現名稱。如果我們想讓它說別的東西,我們可以用這樣的東西來做......
function Child({ data }) {
return (
<p>{data.name ? `The name is: ${data.name}` : "Loading name..."}</p>
);
}
This will ask the component, "is there a value for the data.name property? If yes, then display the text "The name is: ___" where the name is filled in the blank. If no, then display the text "Loading name..."
This is also option 1 for your solution. You can use a ternary operator to provide a default value when the data has not yet arrived.
Another option is to just remove the entire component that relies on the data. Since the return statement will only return items that are truth-y, you can conditionally render your ItemDetail component. Our example might look something like this...
function Parent() {
const [data, setData] = useState({});
useEffect(() => {
fetch('https://api.com')
.then(res => res.json())
.then(setData)
.catch(err => console.error(err));
}, []);
return (
<div>
<h1>Hello!</h1>
{data.name && <Child data={data} />}
</div>
);
}
function Child({ data }) {
return (
<p>The name is: {data.name}</p>
);
}
This is option 2 for your solution. It is quick and easy, but there are distinct differences between how they impact developer and user experience.
作為選項 3,您還可以實作一個加載組件來代替產品組件(包括諸如微調器或進度條之類的東西),但我認為這可能比您的 React 課程要求的作業量更大。
重要的提示。雖然第二個選項肯定更容易,因為您不必為每個欄位撰寫默認值,但有時對于用戶體驗來說可能會更糟,因為當資料加載時整個組件會出現和消失,這可能會導致大的布局變化。
uj5u.com熱心網友回復:
您可以執行以下操作:
在請求完成或...之前不要渲染您的組件
使用加載標志狀態
為“正在加載”標志使用額外的狀態..您可以在“真”上啟動它,完成后將其更改為假并使用資料呈現您的組件。
這是我的例子:
import React, { useState, useEffect } from "react";
const productData = {
id: "4",
name: "Cuarto producto",
description: "Descripcion del cuarto producto",
price: 10,
pictureUrl:
"https://media.istockphoto.com/vectors/thumbnail-image-vector-graphic-vector-id1147544807?k=20&m=1147544807&s=612x612&w=0&h=pBhz1dkwsCMq37Udtp9sfxbjaMl27JUapoyYpQm0anc="
};
const ItemDetailContainer = () => {
const [detailedProduct, setDetailedProduct] = useState({});
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchingData = new Promise((res, rej) => {
setTimeout(() => {
res(productData);
}, 2000);
});
fetchingData.then((res) => {
setDetailedProduct(res);
setLoading(false);
console.log("Se guardaron los datos");
});
fetchingData.catch((err) => {
console.log("Failed");
});
}, []);
if (loading) return "Cargando...";
return (
<>
<h1>Producto detallado</h1>
<ItemDetail product={detailedProduct} />
</>
);
};
export default ItemDetailContainer;
function ItemDetail({ product }) {
return (
<div className="bg-slate-100 w-60 flex flex-col items-center mx-1 px-2 border border-slate-400 text-center">
<span>{product.name}</span>
<img src={product.pictureUrl} width="120" />
<p>{product.description}</p>
<span>${product.price}</span>
</div>
);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/439974.html
標籤:javascript 反应
下一篇:提交按鈕沒有做任何事情
