避免在React Hooks中重新呈现列表

我有一个通过map函数在页面加载时呈现的图像的列表。我希望能够选择一个或多个图像并突出显示它们。此外,所选图像的标题将显示在页面顶部。我遇到的问题是,每次选择图像时,列表似乎都会重新呈现。这是组件:

export default function App() {
  const [images,setImages] = React.useState<Image[]>([]);
  const [selected,setSelected] = React.useState<boolean>(false);
  const [imageTitles,setImageTitles] = React.useState<string[]>([]);

  const handleImageSelection = (title: string,index: number) => {
    setSelected(!selected);
    const imageExists = imageTitles.indexOf(title) !== -1
    if (!imageExists) {
      setImageTitles([...imageTitles,title]);
    } else {
      setImageTitles(imageTitles.filter(str => str !== title));
    }
  }

  return (
    <div>
      {console.log(images)} // The images array renders every time
      <div>{imageTitles.map(title => <p>{title}</p>)}</div>

      <section classname="images">{
        images.map(({ title,image},index) =>
          <img
            style={{
              marginBottom: 4,border: imageTitles.indexOf(title) !== -1 ?
                "4px solid blue" : "",// A selected image is highlighted
              borderRadius: 16
            }}
            src={image}
            alt={image}
            onClick={() => handleImageSelection(title,index)}
          />
        )
      }</section>
    </div>
  );
}

我想知道是否是因为每次选择/取消选择图像时都要更改imageTitles数组的大小(因此更改index值)。

我也这样尝试过useCallback

const handleImageSelection = React.useCallback((title: string,index: number) => {
  setSelected(!selected);
  const imageExists = imageTitles.indexOf(title) !== -1
  if (!imageExists) {
    setImageTitles([...imageTitles,title]);
  } else {
    setImageTitles(imageTitles.filter(str => str !== title));
  }
},[selected,imageTitles])

但是似乎并没有达到目的。我的猜测是因为imagetitles每次都会改变。

那么,出于性能原因,是否有可能避免在每次选择/取消选择图像时重新渲染图像列表?

iCMS 回答:避免在React Hooks中重新呈现列表

由于要在useCallback依赖项中添加selected和imageTitles,因此每次调用useCallback时都会重新创建useCallback,因为它本身设置了selected和imageTitles状态

这里的解决方案是使用setState回调模式,并将空数组作为依赖项传递给useCallback

const handleImageSelection = React.useCallback((title: string,index: number) => {
  setSelected(prevSelected => !prevSelected);


    setImageTitles(prevImageTitles => {
        const imageExists = prevImageTitles.indexOf(title) !== -1;
        if (!imageExists) { 
           return [...prevImageTitles,title];
        } else {
           return prevImageTitles.filter(str => str !== title));
        }
    });

},[]);

还请注意,每次您设置正常状态时,列表都会重新呈现。但是react将优化渲染,并且只会重新渲染那些需要更改的元素。

这里要注意的另一件事是,您必须将键属性传递给映射的值,以使React进一步优化重新渲染

return (
    <div>
      <div>{imageTitles.map(title => <p key={title}>{title}</p>)}</div>

      <section className="images">{
        images.map(({ title,image},index) =>
          <img
            key={title} // any unique value here. If you don't have anything use index
            style={{
              marginBottom: 4,border: imageTitles.indexOf(title) !== -1 ?
                "4px solid blue" : "",// A selected image is highlighted
              borderRadius: 16
            }}
            src={image}
            alt={image}
            onClick={() => handleImageSelection(title,index)}
          />
        )
      }</section>
    </div>
  );
本文链接:https://www.f2er.com/2277652.html

大家都在问