React Router & Link:它不考虑搜索参数(或者我认为如此)
React Router & Link: It does not respect search parameters (or so I think)
我正在创建自己的迷你博客,并正在实现搜索功能。
我使用无头 CMS Strapi。因此,如果我想搜索特定的帖子,我可以将 ?_q=search here
添加到 API 调用以查询这些帖子。
在我的 React 应用程序中,我有一个 Posts
组件将页面中的 URL 转发到 API,这可以通过 window.location.pathname + window.location.search
轻松完成。因此,如果有人转到 https://exampleblog.com/posts?_q=search here
,那么 React 将获取路径名和搜索参数,并将其用于对 Strapi 的 API 调用。我这样做是因为它可以节省很多工作。
对于我的搜索功能,我使用 react-router-dom
中的 Link
组件作为搜索按钮。有状态从文本框中获取值,并更改 Link
组件中 to
属性 的值,以便 to
看起来像 /posts?_q=textbox value
.因为页面的路径名和搜索参数被转发到 API,它应该解析正确的帖子。
我的问题是,如果 URL 中的路径名发生变化(例如 /posts
变为 /categories
之类的内容),Link
组件会呈现页面(哪个是对的)。 但是,如果只有search
参数改变(URL中的?_q=search here
)那么浏览器中的URL改变了,但是没有新渲染。
我还想补充一点,当从具有不同路径名的页面进行搜索时,搜索 100% 有效,因此搜索参数是有效的。但是,如果我在具有相同路径名的页面上执行搜索,则不会。
根据我的观察,我得出的结论是 Link
组件不考虑 URL 中搜索参数的更改。
下面是一些示例代码。
来自 Posts
组件的代码段:
const pathname = window.location.pathname + window.location.search;
const {loading, error, data} = useApi(pathname); // Custom hook to resolve API requests. Already knows the hostname.
// Continued code in this component will render the API result
整个Search
组件:
import React, {useState} from 'react';
import {Link} from 'react-router-dom';
export default function Search() {
const [query, setQuery] = useState('');
return (
<div className="search">
<label>Search</label>
<input type="text" onChange={event => setQuery(event.target.value)}></input>
<Link to={`/posts?_q=${query}`} className="button">
Search
</Link>
</div>
);
}
我的“useApi”自定义挂钩:
export default function useApi(endpoint = '/') {
const URI = process.env.URI;
const [state, setState] = useState({
loading: true,
error: false,
data: null
});
useEffect(() => {
(async () => {
try {
const response = await axios.get(URI + endpoint);
const data = response.data;
setState({
loading: false,
error: false,
data
});
} catch (error) {
setState({
loading: false,
error: true,
data: null
});
}
})();
}, [endpoint]);
return state;
}
如您所见,提供给 useApi 挂钩的端点参数最终将是 window.location.pathname + window.location.search
,这意味着它将跟踪必要的更改,包括搜索参数的更改值。
如往常一样,我们将不胜感激任何帮助。
问题:
当查询参数更改时,组件不会重新呈现,因此不会再次调用 API。
解法:
您应该使用依赖项数组中的查询参数在 useEffect() 挂钩中调用 API,这样每当查询参数更改时,将使用新的查询参数调用 API。
我找到了解决我自己问题的另一种方法!
我仍然相信我对它为什么不起作用的推理。然而,React Router V6 内置了一个更官方的解决方法。我没有在早期版本上测试过这个。
您可以使用 react-router-dom
/react-router
中内置的 useSearchParams
挂钩。
在以下示例中,“?page=”将被定义为搜索参数:
export default function Component() {
const [searchParams, setSearchParams] = useSearchParams({});
const searchObject = Object.fromEntries(searchParams.entries());
const { page } = searchObject;
const pageInt = parseInt(page);
return (
<a onClick={() => {
e.preventDefault(); // To avoid a complete page load.
setSearchParams({ ...searchObject, page: `${pageInt + 1}` }
}}>Update search</a>
);
}
以上代码是我设法实现的高度简化版本,因此请随意优化。 :)
我正在创建自己的迷你博客,并正在实现搜索功能。
我使用无头 CMS Strapi。因此,如果我想搜索特定的帖子,我可以将 ?_q=search here
添加到 API 调用以查询这些帖子。
在我的 React 应用程序中,我有一个 Posts
组件将页面中的 URL 转发到 API,这可以通过 window.location.pathname + window.location.search
轻松完成。因此,如果有人转到 https://exampleblog.com/posts?_q=search here
,那么 React 将获取路径名和搜索参数,并将其用于对 Strapi 的 API 调用。我这样做是因为它可以节省很多工作。
对于我的搜索功能,我使用 react-router-dom
中的 Link
组件作为搜索按钮。有状态从文本框中获取值,并更改 Link
组件中 to
属性 的值,以便 to
看起来像 /posts?_q=textbox value
.因为页面的路径名和搜索参数被转发到 API,它应该解析正确的帖子。
我的问题是,如果 URL 中的路径名发生变化(例如 /posts
变为 /categories
之类的内容),Link
组件会呈现页面(哪个是对的)。 但是,如果只有search
参数改变(URL中的?_q=search here
)那么浏览器中的URL改变了,但是没有新渲染。
我还想补充一点,当从具有不同路径名的页面进行搜索时,搜索 100% 有效,因此搜索参数是有效的。但是,如果我在具有相同路径名的页面上执行搜索,则不会。
根据我的观察,我得出的结论是 Link
组件不考虑 URL 中搜索参数的更改。
下面是一些示例代码。
来自 Posts
组件的代码段:
const pathname = window.location.pathname + window.location.search;
const {loading, error, data} = useApi(pathname); // Custom hook to resolve API requests. Already knows the hostname.
// Continued code in this component will render the API result
整个Search
组件:
import React, {useState} from 'react';
import {Link} from 'react-router-dom';
export default function Search() {
const [query, setQuery] = useState('');
return (
<div className="search">
<label>Search</label>
<input type="text" onChange={event => setQuery(event.target.value)}></input>
<Link to={`/posts?_q=${query}`} className="button">
Search
</Link>
</div>
);
}
我的“useApi”自定义挂钩:
export default function useApi(endpoint = '/') {
const URI = process.env.URI;
const [state, setState] = useState({
loading: true,
error: false,
data: null
});
useEffect(() => {
(async () => {
try {
const response = await axios.get(URI + endpoint);
const data = response.data;
setState({
loading: false,
error: false,
data
});
} catch (error) {
setState({
loading: false,
error: true,
data: null
});
}
})();
}, [endpoint]);
return state;
}
如您所见,提供给 useApi 挂钩的端点参数最终将是 window.location.pathname + window.location.search
,这意味着它将跟踪必要的更改,包括搜索参数的更改值。
如往常一样,我们将不胜感激任何帮助。
问题: 当查询参数更改时,组件不会重新呈现,因此不会再次调用 API。
解法: 您应该使用依赖项数组中的查询参数在 useEffect() 挂钩中调用 API,这样每当查询参数更改时,将使用新的查询参数调用 API。
我找到了解决我自己问题的另一种方法!
我仍然相信我对它为什么不起作用的推理。然而,React Router V6 内置了一个更官方的解决方法。我没有在早期版本上测试过这个。
您可以使用 react-router-dom
/react-router
中内置的 useSearchParams
挂钩。
在以下示例中,“?page=”将被定义为搜索参数:
export default function Component() {
const [searchParams, setSearchParams] = useSearchParams({});
const searchObject = Object.fromEntries(searchParams.entries());
const { page } = searchObject;
const pageInt = parseInt(page);
return (
<a onClick={() => {
e.preventDefault(); // To avoid a complete page load.
setSearchParams({ ...searchObject, page: `${pageInt + 1}` }
}}>Update search</a>
);
}
以上代码是我设法实现的高度简化版本,因此请随意优化。 :)