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>
  );
}

以上代码是我设法实现的高度简化版本,因此请随意优化。 :)