过滤反应组件状态会导致无限渲染循环



我正在使用useEffect从API检索一些数据,我希望能够使用从其父组件馈送到组件中的道具来过滤返回的数据。

我试图在useEffect设置状态后对其进行过滤,但看起来组件将进入无限渲染循环。

我需要做些什么来防止这种情况发生?

export default function HomeJobList(props: Props): ReactElement {
    const [listings, setListings] = React.useState(null);
  
    useEffect(() => {
        const func = async () => {
          let res = await service.getListings();
          setListings(res);
        };
        func();
      }, []);
  
    if (props.searchTerm && listings) {
      let filtered = listings.filter((x) => x.positionTitle.includes(props.searchTerm));
      setListings(filtered);
    }
  
    return (
      <>
        <div>do stuff</div>
      </>
    );
  }
  

我知道,使用setListing函数会在过滤后导致一个reender,然后导致另一个setListing调用。但打破这种循环的最佳方法是什么?

我应该只使用另一个状态值来维护上次用于筛选的searchTerm,并在筛选之前对此进行检查吗?

或者有更好的方法吗?

这是一个独立循环,因为每次过滤时,都将其设置为状态变量,从而导致重新渲染和过滤&再次设置变量-因此是一个循环。

我建议你在一个地方完成所有操作(你的useEffect是一个很好的地方,因为它只执行一次

    useEffect(() => {
        (async () => {
          const res = await service.getListings();
          const filtered = res.filter((x) => x.positionTitle.includes(props.searchTerm));
          setListings(filtered);
        })();
      }, []);

当状态发生变化,触发重新渲染时,这就是为什么会有一个无限循环;你要做的是将你的过滤包装在一个useEffect中,这个useEffect依赖于searchTerm道具,比如:

import React, { useEffect } from 'react';
export default function HomeJobList() {
  const [listings, setListings] = React.useState(null);
  useEffect(() => {
    const func = async () => {
      let res = await service.getListings();
      setListings(res);
    };
    func();
  }, []);
  useEffect(() => {
    if (listings) {
      let filtered = listings.filter(x =>
        x.positionTitle.includes(props.searchTerm)
      );
      setListings(filtered);
    }
  }, [props.searchTerm]);
  return (
    <>
      <div>do stuff</div>
    </>
  );
}

您需要创建一个在返回的JSX内部调用的函数。

实际上,每次Props对象更改时,都需要渲染组件。这是通过调用JSX代码中的函数来实现的。

示例:

功能:

const filteredListings = () => {
    if (props.searchTerm && listings) {
        let filtered = listings.filter((x) => {
            x.positionTitle.includes(props.searchTerm));
        }
        return filtered;
    }
}

退货声明:

return (
    <ul>
        {
            filteredListings().map((listing) =>
                <li>{listing.title}</li> 
            );
        }
    </ul>
);

您需要的是一个useEffect,它在道具更改时进行过滤。

更换此

 if (props.searchTerm && listings) {
      let filtered = listings.filter((x) => x.positionTitle.includes(props.searchTerm));
      setListings(filtered);
    }

带有

useEffect(()=>{
   if (props.searchTerm) {
      setListings(prevListing => {
          return prevListing.filter((x) => x.positionTitle.includes(props.searchTerm))
      });            
    }
}, [props.searchTerm] )

最新更新