实现 ContextProvider 来获取和过滤数据的最佳可扩展方式是什么

问题描述 投票:0回答:1

我一直在开发一个需要获取大量数据并提供多种方法来过滤/搜索数据的项目,考虑到我将使用分页,我想在服务器端保留过滤。

我最近开始使用 React Context 并尝试了一种不起作用的方法。

这是我用来获取数据的自定义 React 钩子

import { useState, useEffect } from 'react';

const useFetch = (url, url_params) => {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    const [refresh, setRefresh] = useState(0);

    if (url_params) {
        url = url + '?' + url_params.toString();
    }

    const refreshData = () => {
        setRefresh((prev) => prev + 1);
    }

    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await fetch(url);
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                const result = await response.json();
                setData(result);
            } catch (error) {
                setError(error);
            } finally {
                setLoading(false);
            }
        };

        fetchData();
    }, [refresh, url]);

    return { data, loading, error, refreshData };
};

export default useFetch;

这是 contextProvider:

import { createContext, useState, useEffect, useContext } from "react";
import { listing_url } from "../../Hooks/api_endpoints";
import useFetch from "../../Hooks/useFetch";
import { useSearchParams } from "react-router-dom";

export const HouseContext = createContext();

export const HouseProvider = ({ children }) => {
    const [selectedHouse, setSelectedHouse] = useState(null);
    // I have tried multiple approaches for searchParams (one is search params and the other is testParams
    const [searchParams, setSearchparams] = useState({
        address__icontains: '',
        apartment_no__icontains: '',
        block__iexact: '',
        currency__iexact: '',
        floor__iexact: '',
        gross__gte: '',
        gross__lte: '',
        net__gte: '',
        net__lte: '',
        num_of_floors__iexact: '',
        num_of_rooms__iexact: '',
        owner__icontains: '',
        owner_phone_num__icontains: '',
        price__gte: '',
        price__lte: '',
        status__iexact: '',
        view__icontains: '',
    });

    // second attempt at implementing searchParams
    const testParams = new URLSearchParams({
        address__icontains: '',
        apartment_no__icontains: '',
        block__iexact: '',
        currency__iexact: '',
        floor__iexact: '',
        gross__gte: '',
        gross__lte: '',
        net__gte: '',
        net__lte: '',
        num_of_floors__iexact: '',
        num_of_rooms__iexact: '',
        owner__icontains: '',
        owner_phone_num__icontains: '',
        price__gte: '',
        price__lte: '',
        status__iexact: '',
        view__icontains: '',
    });

    const { data: houses, error: housesError, loading: housesLoading, refreshData: houseRefresh } = useFetch(listing_url, testParams);

    const createHouse = async (house) => {

        const newHouse = await fetch(listing_url, {
            method: "POST",
            body: JSON.stringify(houseData),
        });
        setHouses([...houses, newHouse]);
    }

    // useEffect(() => {
    //     console.log("houses were updated")
    //     console.log(' search params were updated')
    // }, [houses, testParams])

    const updateSearchParams = (key, value) => {
        console.log("firing updateSearchParams")
        houseRefresh();
        testParams.set(key, value);
    }

    return (
        <HouseContext.Provider value={{ houses, selectedHouse, housesError, housesLoading, setSelectedHouse, createHouse, testParams, updateSearchParams }}>
            {children}
        </HouseContext.Provider>
    )
}

这是我尝试使用主页中的过滤选项的方法:

import { HouseContext } from '../../Context/House/House';

// .....

export default function Home() {
// .....

    const { testParams, updateSearchParams } = useContext(HouseContext)

    // ......
    return (
          // ......

          <div className='flex'>
            <span className='text-sm/3 my-auto pr-2 dark:text-white'>floor</span>
            <input type='number' placeholder='floor' min={0} onChange={(e) => { updateSearchParams('floor__iexact', e.target.value) }} className='w-14 rounded border border-black' />
          </div>
    // .....

现在我对此有两个问题:

  1. 为什么当
    houses
    触发时,
    updateSearchParams
    列表没有更新?
  2. 这种方法是否有效,或者我应该只采取获取数据然后过滤客户端的方式?如果是这样,添加分页后我该怎么做?
javascript reactjs server-side-rendering react-context client-side
1个回答
0
投票

我相信您在这里遇到的问题是由没有触发重新渲染引起的,因此您没有看到房屋有任何变化。
我认为解决此问题的最简单方法如下:

const [testParams, setTestParams] = useState(new URLSearchParams({ ... rest of the tings })

然后更新 updateSearchParams 以执行以下操作,而不是您正在执行的 testParams 设置:

setTestParams(prev => {
    const new = new URLSearchParams(prev);
    new.set(key, value);
    return new;
});

此更改现在应该会导致 React 触发重新渲染,并希望向您展示更新后的房屋。
我也会小心您当前正在执行的 onChange,这可能会导致一些问题并发送大量请求。

© www.soinside.com 2019 - 2024. All rights reserved.