我有一个路径/items
的加载器,它从API获取大量数据,所以我使用延迟加载器.我希望只有在没有搜索查询参数(即从服务器进行初始提取)时才有条件地呈现<Supense><Await>
代码,然后使用已经提取的项并根据搜索查询参数对其进行过滤.
-
/items
—从API提取3秒> - 提交一个表单(例如搜索输入),该表单使用查询参数(例如
search=test
)导航 -
/items?search=test
—根据查询参数,使用useSearchParams
过滤已经提取的项目>
-
Issue:重新渲染组件,再次遍历
<Suspense><Await>
处理这种情况的最佳方法是什么?我try 使用useState,Location State(从<Form state>
开始),但为了使用已经获取的数据,很难不呈现<Await>
.
我是否错过了一个可以在这种情况下使用的有价值的模式?没有一个已经确立的模式似乎太常见了
Update—一个快速的代码示例,使用Form state和Location来初始显示从API获取的项目,而不是基于查询参数过滤的本地保存的项目(search
):
装载机功能:const loader= (() => defer({ itemsAsync: getItems() })) satisfies LoaderFunction; // getItems() is Promise
组件:
const { itemsAsync } = useLoaderData();
const { state: { savedItems } } = useLocation();
const [searchParams] = useSearchParams();
const searchQueryParam = searchParams.get('search')?.toLowerCase() ?? '';
const filterItems = (items: Item[]) => items.filter((item) => item.content.toLowerCase().includes(searchQueryParam));
return state ? (
<div>
<Form state={{savedItems: items}}>
<input type="text" name="search" />
<input type="submit" hidden />
</Form>
{filterItems(state?.items).map((item) => <div>{item}</div>)}
</div>
) : (
<Suspense fallback={<div>Loading items...</div>}>
<Await resolve={itemsAsync}>
{(items) => (
<div>
<Form state={{savedItems: items}}>
<input type="text" name="search" />
<input type="submit" hidden />
</Form>
{items.map((item) => <div>{item}</div>)}
</div>
)}
</Await>
</Suspense>
);
在提交表单时,它只需添加search
作为查询参数/items?search=test
,然后基于测试,我们应该过滤列表并显示获取的项的子集.这不起作用的原因有很多-例如,search
查询参数仅在加载过程的最后添加到URL中,在这种情况下,它从API获取新项(例如,5秒延迟),然后才更新实际的URL.我知道我也可以从加载器的request
获得参数,但然后我将需要根据是否有参数返回非延迟数据?在使用查询参数的同时,必须有一种更简单的方法来处理"缓存"数据,我现在正在重新发明轮子.
正如我已经提到的,我脑海中的理想流是:
-
/items
->;从API获取(慢请求~3秒) - 提交一个表单(例如搜索输入),该表单使用查询参数(例如
search=test
)导航 -
/items?search=test
—根据查询参数过滤已经提取的项目,而不是再次提取相同的项目,然后进行过滤>