【问题标题】:"Warning: Each child in a list should have a unique "key" prop" when adding new element to the list“警告:在列表中添加新元素时,列表中的每个孩子都应该有一个唯一的“关键”道具”
【发布时间】:2021-06-15 04:57:19
【问题描述】:

我正在使用 React、Express (axios) 和 MongoDB 开发项目列表。

列表数组的项目从 MongoDB 中检索,显示在组件中,用户可以添加新项目(并将它们保存在 MongoDB 中)。

问题是 Warning: Each child in a list should have a unique "key" prop" 显示是因为使用 id: Math.random() 属性将新元素添加到列表中(尽管这些 id 没有提交到数据库)

App.tsx(这里使用 MongoDB 生成的 id 获取项目列表

export default function App() {
    const [ExpenseAndAmountList, setExpenseAndAmountList] = useState<
      Array<{
        id: number,
        expenseTitle: string,
        expenseAmount: string,
      }>
    >([]);


 useEffect(() => {
    const expensesListResp = async () => {
      await axios.get('http://localhost:4000/app/expenseslist')
      .then(
        response => setExpenseAndAmountList(response.data && response.data.length > 0 ? response.data : []));
    }
    expensesListResp();
  }, []);

    return (
      <div className="App">
        <ExpenseAmountInputContainer 
          expenseAndAmountList={ExpenseAndAmountList}
          setExpenseAndAmountList={setExpenseAndAmountList}
          setTotalExpensesAmount={setTotalExpensesAmount}
          totalExpenses={TotalExpensesAmount}
        />

        <DynamicList 
          expenseAndAmountList={ExpenseAndAmountList} 
          currencySymbol={Currency}
          setExpenseAndAmountList={setExpenseAndAmountList}
        />
      </div>
    );
}

ExpenseAmountInputContainer.tsx(这里的项目被发布到没有任何 id 的 MongoDB 列表

interface Props {
    expenseAndAmountList: Array<ExpenseAndAmountObject>;
    setExpenseAndAmountList: (value: Array<ExpenseAndAmountObject>) => void; 
}

const ExpenseAmountInputContainer: React.FC<Props> = (
        {
            expenseAndAmountList, 
            setExpenseAndAmountList,
        }: Props
    ) => {
    
    const [Expense, setExpense] = useState<string>('');
    const [Amount, setAmount] = useState<string>('');

    const AddItemToList = () => {
        if (Expense !== '' && Amount !== '' && Number(Amount) > 0) {

            axios.post('http://localhost:4000/app/expenseslist', 
            {
                expenseTitle: Expense,
                expenseAmount: Amount
            });
            
            setExpense("");
            setAmount("");

            const expensesListResp = async () => {
                await axios.get('http://localhost:4000/app/expenseslist')
                .then(
                response => setExpenseAndAmountList(response.data && response.data.length > 0 ? response.data : []));
            }
            expensesListResp();
    }

    return (
        <div>
            <InputItem 
                onChange={setExpense} 
                onBlur={setExpense} 
                title="Expense" 
                type="text" 
                placeholder="Item title" 
                value={Expense}
            />
            <InputItem 
                onChange={setAmount}  
                onBlur={setAmount}  
                title="Amount" 
                type="number" 
                placeholder="Expense cost" 
                value={Amount}
            />
            <AddButton 
                onClick={AddItemToList} 
                content="Add expense"

            />
        </div>
    );
};

export default ExpenseAmountInputContainer;

ExpenseAndAmountObject.tsx(在 ExpenseAmountInputContainer.tsx 使用的接口)

export interface ExpenseAndAmountObject {
    id: number,
    expenseTitle: string,
    expenseAmount: string,
}

DynamicList.tsx

import { ExpenseAndAmountObject } from '../ExpenseAndAmountObject';
  interface ListItemsArray {
    expenseAndAmountList: Array<ExpenseAndAmountObject>;
    currencySymbol: string;
    setExpenseAndAmountList: (value: Array<ExpenseAndAmountObject>) => void;
  }

  const DynamicList: React.FC<ListItemsArray> = (
    {
      expenseAndAmountList, 
      currencySymbol,
      setExpenseAndAmountList
    }: ListItemsArray) => {

    return (
        <>
            <List>
                {expenseAndAmountList.map(item => (
                  <ExpensesListItem
                    expenseTitle={item.expenseTitle} 
                    expenseAmount={item.expenseAmount}
                    currencySymbol={currencySymbol}
                    item={item}
                    items={expenseAndAmountList}
                    setExpenseAndAmountList={setExpenseAndAmountList}
                  />
                ))} 
            </List>
        </>
      );
  }
  
export default DynamicList;

这个问题怎么解决?

【问题讨论】:

  • 您在哪里设置项目 ID 属性?您是否将它们设置在后端? Math.random 确实不是生成唯一 ID 的好用例。
  • 我的评论具有误导性,我没有使用Math.random。 AT ExpenseAmountInputContainer.tsx 项目在没有任何 id 的情况下发布到 MongoDB(因为它们是在 MongoDB 中生成的)
  • 尽管如此,在将新元素添加到列表时,仍不清楚您在哪里添加任何 id 属性。 ids 在哪里生成?错误在哪里抛出?看来您正在后端生成它们。如果它们不是唯一的,那么您将遇到此前端问题。可以看看相关的后端代码吗?
  • 在 DynamicList.tsx 中,您是否为使用 map() 创建的组件设置 key prop?
  • 我没有在任何地方设置 key prop,我只是在&lt;List&gt; 中添加了一个属性key={item.id}。我正在尝试实现该 item.id 将是由 MongoDB 生成的 _id (也许这不是正确的方法..?)

标签: reactjs typescript mongodb list ids


【解决方案1】:

渲染列表时需要传递 key 属性。

import { ExpenseAndAmountObject } from '../ExpenseAndAmountObject';
  interface ListItemsArray {
    expenseAndAmountList: Array<ExpenseAndAmountObject>;
    currencySymbol: string;
    setExpenseAndAmountList: (value: Array<ExpenseAndAmountObject>) => void;
  }

  const DynamicList: React.FC<ListItemsArray> = (
    {
      expenseAndAmountList, 
      currencySymbol,
      setExpenseAndAmountList
    }: ListItemsArray) => {

    return (
        <>
            <List>
                {expenseAndAmountList.map(item => (
                  <ExpensesListItem

                    key={} // <-----  SOME UNIQUE ID HERE!!!!!!!!

                    expenseTitle={item.expenseTitle} 
                    expenseAmount={item.expenseAmount}
                    currencySymbol={currencySymbol}
                    item={item}
                    items={expenseAndAmountList}
                    setExpenseAndAmountList={setExpenseAndAmountList}
                  />
                ))} 
            </List>
        </>
      );
  }
  
export default DynamicList;

请参阅解释此行为的文档https://reactjs.org/docs/lists-and-keys.html#keys

【讨论】:

  • 根据您的示例,我已将属性 key={item.id} 添加到 &lt;List&gt;。 item.id 应该是由 MongoDB 生成的 _id(我已经检查过组件 DynamicList 中的 MongoDB 项目数组是可访问的,即等于 [{_id: "60c970297ba73b083ec13dbc", expenseTitle: “first_title, expenseAmount: "1", __v: 0},{_id: "60c9782dae534110361f359a", expenseTitle: “second”title, expenseAmount: “2”, __v: 0}])。但是,当我检查 ExpensesListItem 中项目的道具值时,key={item.id} equals to undefined 的值。也许你知道为什么?提前致谢!
猜你喜欢
  • 2023-04-07
  • 2019-08-04
  • 2021-01-12
  • 2022-06-28
  • 2023-02-17
  • 2019-12-05
  • 2021-09-05
  • 2020-03-01
  • 2020-03-27
相关资源
最近更新 更多