Javascript 列表子项未正确更新?(反应/预演)

Javascript 列表子项未正确更新?(反应/预演),javascript,reactjs,preact,Javascript,Reactjs,Preact,我有以下组件 import {h, Component} from 'preact' import {getPersons} from '../../lib/datalayer' import Person from '../person' import {SearchInput} from '../search' export default class Persons extends Component { state = { allPersons: [], perso

我有以下组件

import {h, Component} from 'preact'
import {getPersons} from '../../lib/datalayer'
import Person from '../person'
import {SearchInput} from '../search'

export default class Persons extends Component {
  state = {
    allPersons: [],
    persons: [],
    search: ''
  }

  async fetchData () {
    try {
      const allPersons = await getPersons()
      this.setState({allPersons: allPersons.slice(), persons: allPersons.slice()})
    } catch (error) {
      ....
    }
  }

  constructor (props) {
    super(props)
    this.state = {
      allPersons: [],
      persons: [],
      search: ''
    }
    this.fetchData()
  }

  onSearchInput = (search) => {
    if (search === '') {
      this.setState({search: search, persons: this.state.allPersons.slice()})
    } else {
      const persons = this.state.allPersons.filter(p => p.name.toLowerCase().includes(search.toLowerCase())).slice()
      this.setState({search: search, persons: persons)})
    }
  }

  render () {
    const {persons} = this.state
    return (
      <div>
        <SearchInput onInputChange={this.onSearchInput} placeHolder={'filter: name'} />
        {persons.map(p => <Person person={p} />)}
      </div>
    )
  }
}
我在搜索输入中写道:“我们”

过滤器工作正常,结果如下:

[{name: 'marcus'}, {name: 'usa'}] \\ (the expected result)
在页面中,将呈现此对象

[{name: 'thomas'}, {name: 'john'}] \\ (wrong, this are the two first elements of the list)
如果我搜索:“joh”

过滤器的结果是

[{name: 'john'}] \\ (this is fine)
并且页面只呈现

[{name: 'thomas'}] \\ (the first element in the list)
看起来渲染的元素数量不错,但列表中子元素的内容没有被重新渲染


我的代码有什么问题?

React使用列表子项上的
键来确定哪些项已更改,哪些项保持不变。由于您没有在person上指定
,因此需要
索引
作为键

当索引为键时,您可以看到如何将列表缩短为两项,显示列表中的前两项(其他索引现在丢失)。要解决这个问题,您必须在此人身上指定一个唯一标识符作为密钥

从对象中,假设
名称
是唯一的(通常不是):

{persons.map(p=>)}

React使用列表子项上的
键来确定哪些项已更改,哪些项保持不变。由于您没有在person上指定
,因此需要
索引
作为键

当索引为键时,您可以看到如何将列表缩短为两项,显示列表中的前两项(其他索引现在丢失)。要解决这个问题,您必须在此人身上指定一个唯一标识符作为密钥

从对象中,假设
名称
是唯一的(通常不是):

{persons.map(p=>)}

我无法使用react重现错误,确实删除了一些不需要的片段,并为每个元素添加了唯一id(如果您没有给每个元素一个唯一的键,react将投诉,并且可能会预作用)

const Person=React.memo(道具=>(
{JSON.stringify(props,未定义,2)}
));
类。组件{
状态={
所有人士:[
{name:'aaa',id:1},
{name:'aab',id:2},
{name:'abb',id:3},
{name:'bbb',id:4},
{姓名:'bbc',id:5},
],
人员:[
{name:'aaa',id:1},
{name:'aab',id:2},
{name:'abb',id:3},
{name:'bbb',id:4},
{姓名:'bbc',id:5},
],
搜索:“”,
};
onSearchInput=搜索=>{
如果(搜索==''){
//这里不需要切片
这是我的国家({
搜索:搜索,
人物:this.state.allPersons,
});
}否则{
//筛选器已复制所有人员
const persons=this.state.allPersons.filter(p=>
p、 name.toLowerCase().includes(search.toLowerCase())
);
this.setState({search:search,persons:persons});
}
};
render(){
const{persons}=这个州;
返回(
this.onSearchInput(e.target.value)}
占位符={'filter:name'}
/>
{persons.map(p=>(
))}
);
}
}
ReactDOM.render(
,
document.getElementById('root'))
);

我无法使用react重现错误,确实删除了一些不需要的片段,并为每个元素添加了唯一id(如果您没有给每个元素一个唯一的键,react将投诉,并且可能会预作用)

const Person=React.memo(道具=>(
{JSON.stringify(props,未定义,2)}
));
类。组件{
状态={
所有人士:[
{name:'aaa',id:1},
{name:'aab',id:2},
{name:'abb',id:3},
{name:'bbb',id:4},
{姓名:'bbc',id:5},
],
人员:[
{name:'aaa',id:1},
{name:'aab',id:2},
{name:'abb',id:3},
{name:'bbb',id:4},
{姓名:'bbc',id:5},
],
搜索:“”,
};
onSearchInput=搜索=>{
如果(搜索==''){
//这里不需要切片
这是我的国家({
搜索:搜索,
人物:this.state.allPersons,
});
}否则{
//筛选器已复制所有人员
const persons=this.state.allPersons.filter(p=>
p、 name.toLowerCase().includes(search.toLowerCase())
);
this.setState({search:search,persons:persons});
}
};
render(){
const{persons}=这个州;
返回(
this.onSearchInput(e.target.value)}
占位符={'filter:name'}
/>
{persons.map(p=>(
))}
);
}
}
ReactDOM.render(
,
document.getElementById('root'))
);

[{name: 'thomas'}] \\ (the first element in the list)
 {persons.map(p => <Person person={p} key={p.name} />)}