redux 如何防止在react中重新呈现

mqxuamgl  于 2022-11-12  发布在  React
关注(0)|答案(1)|浏览(118)

现在,我已经创建了这个自定义钩子来执行惰性加载,它将redux切片操作作为输入,

import { useState, useEffect, useCallback, useRef } from "react";
import { useDispatch } from "react-redux";

function useLazyFetch(fetchAction) {
  const dispatch = useDispatch();

  const [page, setPage] = useState(1);
  const [loading, setLoading] = useState(false);
  const loadMoreRef = useRef(null);

  const handleObserver = useCallback(async(entries) => {
    const [target] = entries;
    console.log(target.isIntersecting);
    if (target.isIntersecting) {
        console.log("INTERSECTING.....");
        await new Promise((r) => setTimeout(r, 2000));
        setPage((prev) => prev + 1);
    }
  }, []);

  useEffect(() => {
    const option = {
      root: null,
      rootMargin: "0px",
      threshold: 1.0,
    };

    const observer = new IntersectionObserver(handleObserver, option);

    if (loadMoreRef.current) observer.observe(loadMoreRef.current);
  }, [handleObserver]);

  const fetchApi = useCallback(async () => {
    try {
      setLoading(true);
      await new Promise((r) => setTimeout(r, 2000));
      dispatch(fetchAction(page))

      setLoading(false);
    } catch (err) {
      console.error(err);
    }
  }, [page,fetchAction,dispatch]);

  useEffect(() => {
    fetchApi();
  }, [fetchApi]);

  return { loading, loadMoreRef };
}

export default useLazyFetch;

我在我的组件中这样使用它,在这里你可以看到我在底部使用来自useLazyFetch的loadMoreRef跟踪div,现在当我注解掉**fetchApi();**从自定义挂钩它的工作如预期,滚动其日志记录INTERSECTING...在控制台中,但当我试图通过fetchApi()执行该操作时,我的整个应用程序进入循环,div跟踪器与ref来到顶部,它获取帖子,但在该操作立即重复后,跟踪器来到顶部,页面变为空&它获取下一组帖子,我可以看到我的列表在redux开发工具中获得了附加到状态的新帖子集,而不是完全设置新状态,但在UI中,它一次又一次地呈现所有帖子,这导致了循环,我如何才能避免这种情况?

import { CircularProgress, Grid, IconButton, Typography } from "@mui/material";
import { Box } from "@mui/system";
import React, { useEffect,useRef,useState } from "react";
import AssistantIcon from "@mui/icons-material/Assistant";
import Post from "../components/Post";
import { useDispatch, useSelector } from "react-redux";
import { getPosts } from "../redux/postSlice";
import AddPost from "../components/AddPost";

import useLazyFetch from "../hooks/useLazyFetch";

export default function Home() {
  const dispatch = useDispatch();
  // const api =  `https://picsum.photos/v2/list`
  const { status, posts } = useSelector((state) => state.post);
  const {loading,loadMoreRef} = useLazyFetch(getPosts)

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

  return (
    <Box>
      <Box borderBottom="1px solid #ccc" padding="8px 20px">
        <Grid container justifyContent="space-between" alignItems="center">
          <Grid item>
            <Typography variant="h6">Home</Typography>
          </Grid>
          <Grid item>
            <IconButton>
              <AssistantIcon />
            </IconButton>
          </Grid>
        </Grid>
      </Box>
      <Box  height="92vh" sx={{ overflowY: "scroll" }}>
        <AddPost />
        <Box textAlign="center" marginTop="1rem">
          {status === "loading" && (
            <CircularProgress size={20} color="primary" />
          )}
        </Box>
        {status === "success" &&
          posts?.map((post) => <Post key={post._id} post={post} />)}
         <div style={{height:"50px",width:"100px",backgroundColor:"red"}} ref={loadMoreRef}>{loading && <p>loading...</p>}</div>

      </Box>
    </Box>
  );
}

这是我的redux操作和状态更新部分

const initialState = {
  status: "idle",
  posts: []
};

export const getPosts = createAsyncThunk("post/getPosts", async (page) => {
  console.log(page);
  console.log("calling api ...");
  const { data } = await axios.get(`/api/posts?page=${page}`);
  return data;
});

export const postSlice = createSlice({
  name: "post",
  initialState,
  reducers: {},
  extraReducers: {
    [getPosts.pending]: (state, action) => {
      state.status = "loading";
    },
    [getPosts.fulfilled]: (state, action) => {
      state.status = "success";
      state.posts = [...state.posts,...action.payload.response.posts] ;
    },
    [getPosts.rejected]: (state, action) => {
      state.status = "failed";
    },
}
sqserrrh

sqserrrh1#

这是有效的解决方案

import { CircularProgress, Grid, IconButton, Typography } from "@mui/material";
import { Box } from "@mui/system";
import React, { useEffect,useMemo } from "react";
import AssistantIcon from "@mui/icons-material/Assistant";
import Post from "../components/Post";
import { useDispatch, useSelector } from "react-redux";
import { getPosts } from "../redux/postSlice";
import AddPost from "../components/AddPost";
import useLazyFetch from "../hooks/useLazyFetch";

export default function Home() {
  const { status, posts } = useSelector((state) => state.post);
  const {loading,loadMoreRef} = useLazyFetch(getPosts)

const renderedPostList = useMemo(() => (
  posts.map((post) => {
    return( <Post key={post._id.toString()} post={post} />)
  })
), [posts]) 

  return (
    <Box>
      <Box borderBottom="1px solid #ccc" padding="8px 20px">
        <Grid container justifyContent="space-between" alignItems="center">
          <Grid item>
            <Typography variant="h6">Home</Typography>
          </Grid>
          <Grid item>
            <IconButton>
              <AssistantIcon />
            </IconButton>
          </Grid>
        </Grid>
      </Box>
      <Box height="92vh" sx={{ overflowY: "scroll" }}>
        <AddPost />
        <Box textAlign="center" marginTop="1rem">
          {status === "loading" && (
            <CircularProgress size={20} color="primary" />
          )}
        </Box>
        {renderedPostList}
        <div style={{height:"50px",width:"100px",backgroundColor:"red"}} ref={loadMoreRef}>{loading && <p>loading...</p>}</div>
      </Box>
    </Box>
  );
}
}

我用useMemo钩子来记忆,它的工作和预期的一样

相关问题