我有一个搜索页面,当用户搜索某物(例如椅子)时,它会使用 /search-page/chairs
router.push("/search-page/" + searchQuery);
然而,出现的一个问题是,当用户在搜索页面内进行另一次搜索时,URL、地址栏中的查询会更新,但页面不会刷新,因此不会更新产品。
我试过 router.push("/search-page/" + searchQuery, undefined, {shallow: false});
试图强制 router.push 不浅,但这没有用。
我也试过
componentDidUpdate(prevProps){
if(this.state.router.asPath != prevProps.router.asPath){
updateProducts()
}
}
检查组件更新时是否之前的 URL 不等于当前的 URL。 但是,这个 if 语句似乎也不起作用。某些内容未正确更新。 由于我正在使用 NextJS,也许我可以对 getServerSideProps 做些什么?但我不太熟悉 getServerSideProps 或 getIntialProps 的工作原理。 或者也许有一种方法可以更新 URL 中的查询,然后强制刷新页面,就像回调函数一样。 谢谢
答案 0 :(得分:1)
如果有人想知道,我设法通过使用 window.location 来解决
componentDidUpdate() {
var str = window.location.pathname;
var n = str.lastIndexOf('/');
var result = str.substring(n + 1);
if(result != this.state.searchQuery){//if the current URL doesn't match the URL stored in the state (which is the previous url before making a new search)
//grab the query from the current URL, and update the searchQuery state with that query from the current URL
this.updateProducts(result);
}
}
在下面的代码中,当组件更新时,它使用子字符串从 window.location.pathname 中获取查询参数。然后它将来自 window.location 的查询参数与来自 this.state.searchQuery
的查询参数进行比较,如果它们不相同,则使用从 window.location.pathname 中提取的参数更新 this.state.searchQuery
,并调用功能根据用户输入更新产品。
答案 1 :(得分:0)
我使用的一种方法是将返回的 search query JSX
包装在备忘录中,或者将其记住以在更改时更新状态。这是我几个月前在旁边构建的 subreddit 搜索项目的代码
import { FC, useEffect, useMemo, useState } from 'react';
import cn from 'classnames';
import css from './Searchbar.module.css';
import { useRouter } from 'next/router';
import { Input } from '../UI';
import { filterQuery } from '@/lib/helpers';
interface Props {
className?: string;
id?: string;
}
const Searchbar: FC<Props> = ({ className, id = 'r/' }) => {
const router = useRouter();
const [value, setValue] = useState('');
useEffect(() => {
// router.prefetch(url, as)
router.prefetch('/r/[display_name]', `/r/${router.query}`, {
priority: true
});
}, [value]);
return useMemo(
() => (
<div
className={cn(
'relative bg-accents-1 text-base w-full transition-colors duration-150',
className
)}
>
<label className='sr-only' htmlFor={id}>
/r/ - search by subreddit name
</label>
<div className='absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none'>
<span className='text-gray-100 font-semibold sm:text-base'>
/r/
</span>
</div>
<Input
id={id}
name={id}
onChange={setValue}
className={css.input}
defaultValue={
router && router.query ? (router.query.q as string) : ''
}
onKeyUp={e => {
e.preventDefault();
if (e.key === 'Enter') {
const q = e.currentTarget.value;
router.push(
{
pathname: `/r/${q}`,
query: q ? filterQuery({ q }) : {}
},
undefined,
{ shallow: true }
);
}
}}
/>
<div className={css.iconContainer}>
<svg
className={css.icon}
fill='rgb(229, 231, 235)'
viewBox='0 0 20 20'
>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z'
/>
</svg>
</div>
</div>
),
[]
);
};
export default Searchbar;
对应的@/components/Searchbar.module.css
文件
.input {
@apply bg-redditSearch px-3 pl-7 py-2 appearance-none w-full transition duration-150 ease-in-out pr-10 text-gray-100 font-semibold;
@screen sm {
min-width: 300px;
@apply text-lg;
}
@screen md {
min-width: 600px;
@apply text-lg;
}
}
.input:focus {
@apply outline-none text-gray-100;
}
.iconContainer {
@apply absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none;
}
.icon {
@apply h-5 w-5;
}
我在 useEffect 钩子内预取目标路由以增强生产环境中的用户体验;它也将增强开发中的用户体验,但预取目前仅适用于产品。
然后,有一个 @/pages/api
路由处理用户输入的值,如下所示:
@/pages/api/snoosearch.ts
import { Subreddit, Listing } from 'snoowrap';
import { NextApiRequest, NextApiResponse } from 'next';
import { r } from '@/lib/snoo-config';
export type SearchSubreddits = {
subreddit: Listing<Subreddit> | never[];
found: boolean;
};
export default async function (
req: NextApiRequest,
res: NextApiResponse<SearchSubreddits>
) {
const { q } = req.query;
console.log(q);
const data = q
? await r.searchSubreddits({
query: (q as string) ?? 'snowboarding',
count: 10,
limit: 3
})
: [];
res.statusCode = 200;
res.setHeader(
'Cache-Control',
'public, s-maxage=1200, stale-while-revalidate=600'
);
return res.status(200).json({
subreddit: data,
found: true
});
};
因此,此 lambda 注入了动态子目录的 getStaticPaths
以处理实时静态路径生成(如果使用国际化路由,还可以进行可选本地化)并通过 ISR 填充任何给定 subreddit 的内容。
如果您不得不在打字稿环境中使用 Jest 在 Nextjs 中编写测试,您可能熟悉必须通过在测试环境中复制来模拟下一个路由器。这帮助我了解了很多关于路由器内部的知识:
TLDR -- 提交用户搜索的搜索栏的记忆更新状态,强制进行非浅渲染,应该可以解决您的问题
模拟 Nextjs 路由器// Mocks useRouter
type PrefetchOptions = {
priority?: boolean;
locale?: string | false;
};
const useRouter = jest.spyOn(
require('next/router'),
'useRouter'
);
/**
* mockNextUseRouter
* Mocks the useRouter React hook from Next.js on a test-case by test-case basis
*/
export function mockNextUseRouter(props: {
route: string;
prefetch(
url: string,
asPath?: string,
options?: PrefetchOptions
): Promise<void>;
pathname: string;
query: string;
asPath: string;
}) {
useRouter.mockImplementationOnce(() => ({
route: props.route,
prefetch: props.prefetch,
pathname: props.pathname,
query: props.query,
asPath: props.asPath
}));
}