问题描述
我正在开发食谱应用程序,但在从Firebase阵列渲染我的成分列表时遇到一些问题。我是JS和React的新手,所以如果这很简单,我深表歉意。我非常感谢所提供的任何帮助!我已经附上了我的代码,并提供了当前如何呈现数组的示例。我还提供了Firebase数据结构的屏幕截图。 [firebaseStructure] [1]
useEffect(() =>{
database.collection('recipes').onSnapshot(snapshot => {
setRecipeCard(snapshot.docs.map(doc => ({id:doc.id,recipes:doc.data()})));
console.log(snapshot.docs.map(doc => ({id:doc.id,recipes:doc.data()})))
})
},[]);
useEffect(() =>{
database.collection('recipes').onSnapshot(snapshot =>{
setIngredientsList(snapshot.docs.map(doc =>({id:doc.id,ingredient: doc.data().ingredients1})));
console.log(snapshot.docs.map(doc =>({id:doc.id,ingredient: doc.data().ingredients1})))
})
},[]);
return (
<div>
<Container>
<Row>
{recipeCard.map(recipes =>(
<Col md={4} key={recipes.id}>
<Card style={{ width: '100%' }}>
<Card.Img variant="top" src={recipes.recipes.url} style={{height:'300px',width:'100%'}} />
<Card.Body>
<Card.Title>{recipes.recipes.title}</Card.Title>
{/**<Card.Text> **/}
<ul key={recipes.id}>
{ingredientsList.map(recipes =>(
<li key={recipes.id}>
{recipes.ingredient}
</li>
))}
</ul>
{/** </Card.Text> **/}
<Button variant="secondary">Head to Recipe</Button>
</Card.Body>
</Card>
</Col>
))}
</Row>
</Container>
</div>
)
}
[current rendered output][2]
[1]: https://i.stack.imgur.com/bFBdr.png
[2]: https://i.stack.imgur.com/xU1fC.png
解决方法
您不需要在两个单独的useEffect
中两次调用数据库来执行所需的操作。在这种情况下,为了提高效率,您只需调用一次DB。
此外,您还要在第二个映射中声明recipes
,这可能会导致错误,您应该避免对不同的变量使用相同的变量名。您的问题可能与此有关。假设您仅将第一个useEffect
与setRecipeCard
一起使用,我编辑了以下代码。
{recipeCard.map(recipe =>(
<Col md={4} key={recipe.id}>
<Card style={{ width: '100%' }}>
<Card.Img variant="top" src={recipe.recipes.url} style={{height:'300px',width:'100%'}} />
<Card.Body>
<Card.Title>{recipe.recipes.title}</Card.Title>
{/**<Card.Text> **/}
<ul key={recipe.id}>
{recipe.ingredients1.map(ingredient =>(
<li key={recipes.id}>
{ingredient}
</li>
))}
</ul>
{/** </Card.Text> **/}
<Button variant="secondary">Head to Recipe</Button>
</Card.Body>
</Card>
</Col>
))}
您可以试用此代码吗?如果您遇到任何错误,请具体告诉我们:)
,我认为,此处的许多混淆来自命名约定,以及尝试为recipieCard
和ingredientsList
使用单独的状态。您最终呈现了所有食谱的所有要素,而不仅仅是与该食谱相关的要素。如果您发现自己访问诸如recipies.recipies
之类的属性,那么就知道需要进行一些重构(如果您完全控制了项目)。
首先,您只需要一个useEffect
即可访问数据库并处理数据。它们都属于同一类,因此无需将其分成单独的状态。请注意,我是如何将状态重命名为recipieCards
的复数形式。这是数据对象的数组或列表,因此应具有多个名称。现在,每个数据对象都具有属性data
而不是recipies
,该属性可以更准确地描述其包含的内容(即,一个配方的数据)。
useEffect(() =>{
database.collection('recipes').onSnapshot(snapshot => {
setRecipeCards(snapshot.docs.map(doc => ({id:doc.id,data:doc.data()})));
console.log(snapshot.docs.map(doc => ({id:doc.id,data:doc.data()})))
})
},[]);
现在,在返回函数中,发生的事情变得更加清楚。我们采用recipieCards
数组并对其进行映射,以一次访问每个收件人数据对象。对于每个数据对象,请使用id
作为其键,并从data
中获取url和标题。现在,您可以直接在属性data.ingredients1
下从同一数据对象访问该食谱的成分。
return (
<div>
<Container>
<Row>
{recipeCards.map(recipe =>(
<Col md={4} key={recipe.id}>
<Card style={{ width: '100%' }}>
<Card.Img variant="top" src={recipe.data.url} style={{height:'300px',width:'100%'}} />
<Card.Body>
<Card.Title>{recipe.data.title}</Card.Title>
{/**<Card.Text> **/}
<ul>
{recipie.data.ingredients1.map(ingredient =>(
<li key={ingredient}>
{ingredient}
</li>
))}
</ul>
{/** </Card.Text> **/}
<Button variant="secondary">Head to Recipe</Button>
</Card.Body>
</Card>
</Col>
))}
</Row>
</Container>
</div>
);