Javascript 添加新项时,React会重新呈现数组中的所有项,尽管对所有项使用唯一键 原职
我有一个页面,它使用array.prototype.map呈现redux状态中包含的数组中的每个项。数组最初在调用componentWillMount()回调时填充,然后在用户请求更多数据时(即,当用户滚动到页面底部以及如果有更多项目要提取时)追加。我确保在使用array.prototype.concat()对数组进行apping时,redux状态不会发生变化。但是,当向数组中添加更多项时,似乎react会重新呈现数组中的每个项,而不仅仅是新项,尽管为每个项设置了唯一的键。我用于呈现组件的源代码如下所示:Javascript 添加新项时,React会重新呈现数组中的所有项,尽管对所有项使用唯一键 原职,javascript,reactjs,redux,react-redux,rerender,Javascript,Reactjs,Redux,React Redux,Rerender,我有一个页面,它使用array.prototype.map呈现redux状态中包含的数组中的每个项。数组最初在调用componentWillMount()回调时填充,然后在用户请求更多数据时(即,当用户滚动到页面底部以及如果有更多项目要提取时)追加。我确保在使用array.prototype.concat()对数组进行apping时,redux状态不会发生变化。但是,当向数组中添加更多项时,似乎react会重新呈现数组中的每个项,而不仅仅是新项,尽管为每个项设置了唯一的键。我用于呈现组件的源代码
this.props.state.list.map((item, index) => {
return (
<Grid className={classes.column} key={item._id} item xs={6} sm={6} md={4}>
<Card className={classes.card}>
<CardActionArea className={classes.cardAction}>
<div className={classes.cardWrapper}>
<div className={classes.outer}>
<div className={classes.bgWrapper}>
<img
className={[classes.bg, "lazyload"].join(" ")}
data-sizes="auto"
data-src={genSrc(item.pictures[0].file)}
data-srcset={genSrcSet(item.pictures[0].file)}
alt={item.name}
/>
</div>
</div>
<CardContent className={classes.cardContent}>
<div className={classes.textWrapper}>
<div className={classes.textContainer}>
<Typography
gutterBottom
className={[classes.text, classes.title].join(" ")}
variant="title"
color="inherit"
>
{item.name}
</Typography>
<Typography
className={[classes.text, classes.price].join(" ")}
variant="subheading"
color="inherit"
>
{item.minPrice === item.maxPrice
? `$${item.minPrice.toString()}`
: `$${item.minPrice
.toString()
.concat(" - $", item.maxPrice.toString())}`}
</Typography>
</div>
</div>
</CardContent>
</div>
</CardActionArea>
</Card>
</Grid>
);
});
我从与我类似的问题的答案中了解到,为从数组生成的每个组件设置shouldComponentUpdate()方法可能会起到作用,但没有明确的示例说明如何做到这一点。我真的很感激你的帮助。谢谢
编辑1
我还应该指定,当向数组中添加新项时,从数组中呈现的组件将完全卸载并再次装载到浏览器DOM中。理想情况下,我希望浏览器永远不要卸载现有组件,而只附加新渲染的组件
编辑2
下面是呈现列表的组件的完整代码
class Products extends React.Component {
componentDidMount() {
const { fetchNext, fetchStart, filter } = this.props
fetchStart(filter)
window.onscroll = () => {
const { errors, cursor, status } = this.props.state
if (errors.length > 0 || status === 'PENDING' || cursor === null) return
if (window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight) {
fetchNext(filter, cursor)
}
}
}
render() {
const { classes, title } = this.props
return (
<div className={classes.container}>
<Grid container spacing={0}>
{
this.props.state.status && this.props.state.status === 'READY' && this.props.state.list &&
this.props.state.list.map((item, index) => {
return (
<Grid className={classes.column} key={item._id} item xs={6} sm={6} md={4}>
<Card className={classes.card}>
<CardActionArea className={classes.cardAction}>
<div className={classes.cardWrapper}>
<div className={classes.outer}>
<div className={classes.bgWrapper}>
<img className={[classes.bg, 'lazyload'].join(' ')} data-sizes='auto' data-src={genSrc(item.pictures[0].file)} data-srcset={genSrcSet(item.pictures[0].file)} alt={item.name} />
</div>
</div>
<CardContent className={classes.cardContent}>
<div className={classes.textWrapper}>
<div className={classes.textContainer}>
<Typography gutterBottom className={[classes.text, classes.title].join(' ')} variant="title" color='inherit'>
{item.name}
</Typography>
<Typography className={[classes.text, classes.price].join(' ')} variant='subheading' color='inherit'>
{item.minPrice === item.maxPrice ? `$${item.minPrice.toString()}` : `$${item.minPrice.toString().concat(' - $', item.maxPrice.toString())}`}
</Typography>
</div>
</div>
</CardContent>
</div>
</CardActionArea>
</Card>
</Grid>
)
})
}
</Grid>
</div>
)
}
}
类产品扩展了React.Component{
componentDidMount(){
const{fetchNext,fetchStart,filter}=this.props
fetchStart(过滤器)
window.onscroll=()=>{
const{errors,cursor,status}=this.props.state
if(errors.length>0 | | status=='PENDING'| | cursor==null)返回
if(window.innerHeight+document.documentElement.scrollTop==document.documentElement.offsetHeight){
fetchNext(过滤器、光标)
}
}
}
render(){
const{classes,title}=this.props
返回(
{
this.props.state.status&&this.props.state.status==='READY'&&this.props.state.list&&
this.props.state.list.map((项目,索引)=>{
返回(
{item.name}
{item.minPrice===item.maxPrice?`${item.minPrice.toString()}`:`${item.minPrice.toString().concat('-$',item.maxPrice.toString())}`}
)
})
}
)
}
}
因此,原来是条件渲染导致渲染列表消失。在我的例子中,我将其设置为只有在所有正在进行的获取操作都已完成的情况下,组件才会呈现列表,因此在获取调用之间列表当然会消失
将以下内容从
{
this.props.state.status && this.props.state.status === 'READY' && this.props.state.list &&
this.props.state.list.map((item, index) => {
return <Item />
}
}
{
this.props.state.status&&this.props.state.status==='READY'&&this.props.state.list&&
this.props.state.list.map((项目,索引)=>{
返回
}
}
因此,删除对已完成获取状态的检查解决了我的问题
{
this.props.state.list &&
this.props.state.list.map((item, index) => {
return <Item />
}
}
{
this.props.state.list&&
this.props.state.list.map((项目,索引)=>{
返回
}
}
如果状态更改,组件及其所有子组件将重新加载。这很正常。但是,渲染并不意味着这些组件将卸载/装载或销毁/重新创建。这将只发生在更改的部分。这与相关。因此,渲染成本不太高,DOM操作是。但是,如果您确定渲染所有组件时软管组件会造成一些性能损失,您可以检查shouldComponentUpdate
(小心,有时触摸它会导致性能下降),或者您可以使用PureComponent。如果是这种情况,那么我应该了解更多信息:)我认为在这种情况下只会发生重新命名,而不是所有的DOM操作。我知道React会添加或删除子项,但我不认为在这种情况下所有的DOM都会更改。这也是我所期望的。我非常确定我做错了什么。无论如何,再次感谢您在说“消失并重新命名”时的评论eappear,您的意思是加载时将从可见变为消失?您是否对reducer上的status字段做了任何可能导致列表项不显示的操作?发布整个组件代码而不仅仅是列表渲染可能会有所帮助。您可以编写一个纯组件
,只渲染地图项并传递iTEM作为该组件的道具,并查看是否发生了相同的事情。更多参考
{
this.props.state.list &&
this.props.state.list.map((item, index) => {
return <Item />
}
}