代码之家  ›  专栏  ›  技术社区  ›  maaartinus

了解使用不良反应密钥的后果

  •  0
  • maaartinus  · 技术社区  · 4 年前

    最近,我犯了一个小错误,对键使用数组值而不是索引,如下所示:

    import React, { useState } from 'react';
    import ReactDOM from 'react-dom';
    
    function NamesView(props: {names: string[], setNames(l: string[]) : void}) {
        const {names, setNames} = props;
        function setName(index: number, name: string) {
            setNames(names.map((n, i) => i===index ? name : names[i]));
        }
        return <div>
            {/***** THE key IS WRONG!!! */ }
            {names.map((n, i) => <input key={n} value={n} onChange={e => setName(i, e.target.value)}/>)}
        </div>;
    }
    
    function MainView() {
        const [names, setNames] = useState(() => ['one', 'two']);
        return <NamesView names={names} setNames={setNames}/>
    }
    
    ReactDOM.render(<MainView/>, document.getElementById('root'));
    

    在这里,使用 key={i} 那就对了。我不明白的是错误代码的行为:每个输入只能编辑一次。你可以添加或删除一个字符或粘贴一些东西,它就会起作用,但所有后续的更改都会被忽略——直到你改变焦点。

    有人能解释一下原因吗?

    0 回复  |  直到 4 年前
        1
  •  2
  •   Utsav Patel    4 年前

    当您通过映射时 names 其是输入值的数组。 您将按以下方式呈现输入。

    return (
      <div>
        {/***** THE key IS WRONG!!! */}
        {names.map((n, i) => (
          <input key={n} value={n} onChange={(e) => setName(i, e.target.value)} />
        ))}
      </div>
    );
    

    一旦更改输入, setNames 是通过您的 setName 通过 onChange .

    这意味着 react 现在将检查生成的新项目。

    自从 key={n} 会改变输入本身,即现在在dom中生成并更新一个新的输入元素,这就是为什么每次更改它时都会失去焦点。

    当您使用时,情况并非如此 index 作为关键。 因为这样输入的键保持不变,只有值发生了变化。

    然而,使用索引作为键也有一些注意事项。

    你可以在这里阅读更多关于它们的信息:

    1. https://reactjs.org/docs/lists-and-keys.html
    2. https://reactjs.org/docs/reconciliation.html#recursing-on-children
        2
  •  1
  •   Stephan Olsen    4 年前

    键用于列表,以帮助React识别哪些项目已更改、添加或删除。在您的情况下,您使用名称作为键,因此每当您更新输入字段的值时,键也会更新。React检测到这是一个元素被删除,一个新元素被添加。

    因此,React实际上删除了输入字段,并再次添加了一个输入字段,而不仅仅是更新值,这就是为什么在更新其中一个输入后,输入会失去焦点的原因。