如何在React,Redux中部分获取数据? [英] How to fetch data partially in react, redux?

查看:82
本文介绍了如何在React,Redux中部分获取数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

动作

import { FETCH_BLOG, FETCH_BLOG_ERROR, FETCH_BLOG_LOADING } from "../constants/blogActionTypes"
    
    const initialState = {
        blogs: [],
    error: '',
    loading: false,
    allBlogs: []
}
// eslint-disable-next-line import/no-anonymous-default-export
export default (blogs = initialState, action) => {
    switch (action.type) {
        case FETCH_BLOG_LOADING:
            return {
                blogs: [...blogs.blogs],
                loading: true,
                error: ''
            };
        case FETCH_BLOG_ERROR:
            return {
                blogs: [...blogs.blogs],
                loading: false,
                error: action.payload
            };
        case FETCH_BLOG:
            return {
                blogs: [...action.payload, ...blogs.blogs],
                loading: false,
                error: ''
            };
        default: return blogs;
    }
}

减速器

export const fetchBlogs = (data) => async (dispatch) =>{

    dispatch({ type: FETCH_BLOG_LOADING, payload: true })
    fetch('http://localhost:5000/blog?show=' + data, {
        method: 'GET',
        headers: {
            authorization: userData.token
        }
    })
        .then(res => res.json())
        .then(data => {
            if (data.message) {
                dispatch(fetchBlogsError(data.message))
            } else {
                dispatch({ type: FETCH_BLOG, payload: data })
            }
        })
}

反应

const [fetchData, setFetchData] = useState(0);
    const showData = () => {
        setFetchData(fetchData + 10)
    }

    const dispatch = useDispatch();

    const { loading, error, blogs, } = useSelector(state => state.blogs)
  
    const getData = useCallback(  () => {
        dispatch(fetchBlogs(fetchData))
    }, [fetchData])

    useEffect(() => {
        getData()
    }, [getData])

在第一个渲染中,我获取了10个项目.单击更多加载后,我从数据库中获取了另外10个数据.在Blog组件上可以,但是返回首页并返回Blog页面之后;博客项目重复.如何解决这个重复的问题>

On the first render, I fetch 10 items.after clicking on load more I fetch another 10 data from database. On the blog component it's fine but after go back to the home page and get back to the blog page; the blog items duplicates. How to fix this duplicate issue>

推荐答案

这里有两个相互关联的问题,根据您处理#1的方式,您可能不需要解决#2.

There are two issues here which are inter-related, you possibly don't need to address #2 depending on how you address #1.

  1. 您应该在重击操作中添加一个条件,以免获取之前已获取的页面.
  2. 您应按页面分隔博客项,这样,如果两次获取第1页,就不会总是将最新项附加在数组的末尾.

旁注: [... blogs.blogs] 是不必要的,因为有理由克隆您未更改的属性.

Sidenote: [...blogs.blogs] is unnecessary because there is reason to clone properties which you aren't changing.

我对您的API调用感到困惑.看起来/blog?show = 20 正在获得21-30的帖子,但是我想根据名称 show 可以认为是1-20.

I'm confused by your API calls. It looks like /blog?show=20 is getting posts 21-30 but I would think based on the name show that it would be posts 1-20.

使用位置索引:

import { createAsyncThunk, createReducer } from "@reduxjs/toolkit";

export const fetchBlogs = createAsyncThunk(
  "blogs/fetchBlog",
  async (startIndex, { getState, rejectWithValue }) => {
    const res = await fetch("http://localhost:5000/blog?show=" + startIndex, {
      method: "GET",
      headers: {
        // where does userData come from ??
        authorization: userData.token
      }
    });
    const data = await res.json();
    if (data.message) {
      rejectWithValue(data.message);
    } else {
      return data;
    }
  },
  {
    condition: (startIndex, { getState }) => {
      const { blogs } = getState();
      // cancel if loading of if first post on paage is loaded
      if (blogs.loading || blogs.blogs[startIndex]) {
        return false;
      }
    }
  }
);

const initialState = {
  blogs: [],
  error: "",
  loading: false
};

export default createReducer(initialState, (builder) =>
  builder
    .addCase(fetchBlogs.pending, (state) => {
      state.loading = true;
      state.error = "";
    })
    .addCase(fetchBlogs.rejected, (state, action) => {
      state.loading = false;
      state.error = action.payload ?? action.error;
    })
    .addCase(fetchBlogs.fulfilled, (state, action) => {
      const startIndex = action.meta.arg;
      const newBlogs = action.payload;
      // insert in the array at the correct position
      state.blogs.splice(startIndex, newBlogs.length, newBlogs);
    })
);

使用分开的页面:

import { createAsyncThunk, createReducer, createSelector } from "@reduxjs/toolkit";

export const fetchBlogs = createAsyncThunk(
  "blogs/fetchBlog",
  async (pageNumber, { getState, rejectWithValue }) => {
      const startIndex = 10 * (pageNumber - 1);
    const res = await fetch("http://localhost:5000/blog?show=" + startIndex, {
      method: "GET",
      headers: {
        // where does userData come from ??
        authorization: userData.token
      }
    });
    const data = await res.json();
    if (data.message) {
      rejectWithValue(data.message);
    } else {
      return data;
    }
  },
  {
    condition: (pageNumber, { getState }) => {
      const { blogs } = getState();
      // cancel if loading of if there is a property for this page
      if (blogs.loading || blogs.blogs[pageNumber]) {
        return false;
      }
    }
  }
);

const initialState = {
  //arrays keyed by page number
  blogs: {},
  error: "",
  loading: false
};

export default createReducer(initialState, (builder) =>
  builder
    .addCase(fetchBlogs.pending, (state) => {
      state.loading = true;
      state.error = "";
    })
    .addCase(fetchBlogs.rejected, (state, action) => {
      state.loading = false;
      state.error = action.payload ?? action.error;
    })
    .addCase(fetchBlogs.fulfilled, (state, action) => {
      const pageNumber = action.meta.arg;
      state.blogs[pageNumber] = action.payload;
    })
);

// want to flatten the blogs array when selecting
// create a memoized selector
export const selectBlogs = createSelector(
    state => state.blogs,
    (blogsState) => ({
        ...blogsState,
        blogs: Object.values(blogsState.blogs).flat(1)
    })
)

带有组件:

export default () => {
  const [pageNumber, setPageNumber] = useState(1);

  const showNext = () => {
    setPageNumber((page) => page + 1);
  };

  const dispatch = useDispatch();

  const { loading, error, blogs } = useSelector(selectBlogs);

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

这篇关于如何在React,Redux中部分获取数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆