React - 警告:列表中的每个孩子都应该有一个唯一的“关键”道具

Posted

技术标签:

【中文标题】React - 警告:列表中的每个孩子都应该有一个唯一的“关键”道具【英文标题】:React - Warning: Each child in a list should have a unique "key" prop 【发布时间】:2020-03-01 05:12:44 【问题描述】:

在这个简单的 React App 中,我不明白为什么会收到以下警告消息:

警告:列表中的每个孩子都应该有一个唯一的“key”属性。

在我看来,我把密钥放在了正确的位置,形式为 key=item.login.uuid

我怎样才能摆脱警告信息? 把钥匙放在哪里合适?

App.js

import UserList from './List'

const App = props => 
  const [id, newID] = useState(null)
  return (
    <>
      <UserList id=id setID=newID />
    </>
  )


export default App

List.js

const UserList = ( id, setID ) => 
  const [resources, setResources] = useState([])

  const fetchResource = async () => 
    const response = await axios.get(
      'https://api.randomuser.me'
    )
    setResources(response.data.results)
  

  useEffect(() => 
    fetchResource()
  , [])

  const renderItem = (item, newID) => 

    return (
      <>
        newID ? (
          // User view
          <div key=item.login.uuid>
            <div>
              <h2>
                item.name.first item.name.last
              </h2>
              <p>
                item.phone
                <br />
                item.email
              </p>
              <button onClick=() => setID(null)>
                Back to the list
              </button>
            </div>
          </div>
        ) : (
          // List view
          <li key=item.login.uuid>
            <div>
              <h2>
                item.name.first item.name.last
              </h2>
              <button onClick=() => setID(item.login.uuid)>
                Details
              </button>
            </div>
          </li>
        )
      </>
    )
  

  const user = resources.find(user => user.login.uuid === id)

  if (user) 
    // User view
    return <div>renderItem(user, true)</div>
   else 
    // List view
    return (
      <ul>
        resources.map(user => renderItem(user, false))
      </ul>
    )
  


export default UserList

【问题讨论】:

【参考方案1】:

key 需要位于循环内的根级元素上。在您的情况下,这就是片段 (&lt;&gt;)。

要做到这一点,您需要完整地写出来:

const renderItem = (item, newID) => 

  return (
    <Fragment key=item.login.uuid>
      newID ? (
        ...
      )
    </Fragment>
  );

(您可以将Fragment 添加到来自react 的其他导入)。

请注意,您的示例中实际上不需要该片段,您可以删除它并将keys 保留在它们所在的位置,此后&lt;div&gt;&lt;li&gt; 将成为根元素:

const renderItem = (item, newId) => 

  return newID ? (
    <div key=item.login.uuid>
      ...
    </div>
  ) : (
    <li  key=item.login.uuid>
      ...
    </li>
  )

【讨论】:

【参考方案2】:

如果您创建 2 个单独的组件,一个用于用户视图,一个用于列表项,该怎么办。这样你只需要传递用户道具。另外,使用 JSX 并从那里传递 wht 键。

const UserList = ( id, setID ) => 
  const [resources, setResources] = useState([])

  const fetchResource = async () => 
    const response = await axios.get(
      'https://api.randomuser.me'
    )
    setResources(response.data.results)
  

  useEffect(() => 
    fetchResource()
  , [])

  const User = (user) => (
    <div key=user.login.uuid>
      <div>
        <h2>
          user.name.first user.name.last
        </h2>
        <p>
          user.phone
          <br />
          user.email
        </p>
        <button onClick=() => setID(null)>
          Back to the list
        </button>
      </div>
    </div>
  )

  const ListItem = (user) => (
    <li key=user.login.uuid>
      <div>
        <h2>
          user.name.first user.name.last
        </h2>
        <button onClick=() => setID(user.login.uuid)>
          Details
        </button>
      </div>
    </li>
  )

  const user = resources.find(user => user.login.uuid === id)

  if (user) 
    // User view
    return <User user=user</div>
   else 
    // List view
    return (
      <ul>
        resources.map((user, index) => <ListItem key=index user=user />)
      </ul>
    )
  


export default UserList

【讨论】:

以上是关于React - 警告:列表中的每个孩子都应该有一个唯一的“关键”道具的主要内容,如果未能解决你的问题,请参考以下文章

警告:列表中的每个孩子在 React.js 中都应该有一个唯一的“key”道具

如何修复警告:列表中的每个孩子都应该有一个唯一的“关键”道具

警告:列表中的每个孩子都应该有一个唯一的“关键”道具。反应.js

反应:警告列表中的每个孩子都应该有一个唯一的键[重复]

“警告:列表中的每个子项在 React (TypeScript) 中都应该有一个唯一的“键”道具”

正在渲染对象数组的数组,不断收到“警告:列表中的每个孩子都应该有一个唯一的“关键”道具。”