Pass Redux selector value to react state without rerendering in useEffect

Viewed 51

I want to build simple scroll pagination, so I update currentState with oldState and add new data to old state, meanwhile this new data comes from redux selector,

const Posts = () => {
  const [page, setpage] = useState(1);
  const [currentPosts, setCurrentPosts]: any = useState([]);
  const dispatch = useDispatch();

  const postList = useSelector((state: any) => state.posts);
  const { loading = true, error, posts = [] }: IPostList = postList;

  const handleClick = (id: number) => {
    dispatch(listComments(id));
  };
  const handleScroll = (event: any) => {
    const { scrollTop, clientHeight, scrollHeight } = event.currentTarget;
    if (scrollHeight - scrollTop === clientHeight) {
      setpage((prev) => prev + 1);
    }
  };

  useEffect(() => {
    dispatch(listPosts(page));
    setCurrentPosts((prev: any) => [...prev, ...posts]);
  }, [dispatch, page, posts]);

  return (
    <div onScroll={handleScroll} className="posts">
      {posts.map((post, index) => (
        <PostCard
          onClick={() => handleClick(post.id)}
          data={post}
          key={index}
        />
      ))}
    </div>
  );
};

export default Posts;

I understand it causes an infinite loop because whenever posts are updated, listPosts are called, then it's updated again and again.

Can you provide me with the right solution and explanation on how to update currentPosts state while spreading the old state and new state which comes from the redux selector? I think the code says more than my explanation.

1 Answers

Can you run this as two different effects? I believe this should eliminate the infinite loop.

useEffect(() => {
  dispatch(listPosts(page));
}, [dispatch, page]);

useEffect(() => {
  setCurrentPosts((prev: any) => [...prev, ...posts]);
}, [posts]);
Related