Javascript 添加新项时,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会重新呈现数组中的每个项,而不仅仅是新项,尽管为每个项设置了唯一的键。我用于呈现组件的源代码

我有一个页面,它使用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 />
        }
    }