reactjs React Router 6中的搜索参数

yvgpqqbh  于 2023-02-12  发布在  React
关注(0)|答案(1)|浏览(141)

我在实现搜索参数时遇到了react-router@6问题。
首先,应用可以使用搜索表单进行搜索(例如,如果用户搜索dark,应用将定向到localhost:3000/search?query=dark以显示结果),
我也可以使用搜索栏中的URL来定向到正确的页面和结果(比如用户使用的URL是localhost:3000/search?query=dark,它会直接跳转到页面显示结果),现在的问题是用户在搜索表单中输入时,它会立即添加搜索参数来更改URL,我知道这是由于handleChange函数中的setSearchParams()造成的。但是有没有什么方法可以在输入搜索表单时***不***更改URL?

import React from 'react'
import Navbar from './Navbar'
import create from 'zustand'
import { useState, useEffect } from 'react'
import { useLocation, useNavigate, useSearchParams } from 'react-router-dom'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faTriangleExclamation } from '@fortawesome/free-solid-svg-icons'

// Zustand
let store = (set) => ({
  // input: '',
  // setInput: (value) => set({ input: value }),
  allImages: [],
  setAllImages: (images) => set({ allImages: images}),
  totalResults: null,
  setTotalResults: (num) => set({ totalResults: num}),
})
export const useMain = create(store)

function Header() {
  const [error, setError] = useState(null)
  const [showError, setShowError] = useState(false)
  const [fadeOut, setFadeOut] = useState(false)
  const [page, setPage] = useState(1)
  const [searchParams, setSearchParams] = useSearchParams()
  const query = searchParams.get('query') || ''
  const allImages = useMain(state => state.allImages)
  const setAllImages = useMain(state => state.setAllImages)
  // const totalResults = useMain(state => state.totalResults)
  const setTotalResults = useMain(state => state.setTotalResults)

  function handleChange(event) {
    // setInput(event.target.value)
    setSearchParams({query: event.target.value})
  }

  async function fetchImages() {
    try {
      const res = await fetch(`https://api.unsplash.com/search/photos?&page=${page}&per_page=30&query=${query}&client_id=${process.env.REACT_APP_UNSPLASH_API_KEY}`)
      const data = await res.json()
      if (data.total !== 0) {
        setAllImages(data.results)
        setTotalResults(data.total)
      }
    } catch(error) {
      setError(error)
    }
  }

  let navigate = useNavigate()
  const handleSubmit = async (event) => {
    event.preventDefault()
    fetchImages()
    navigate(`/search?query=${query}`)
  }

  const location = useLocation()
  useEffect(() => {
    if (location.pathname === '/search' && allImages.length === 0) {
      fetchImages()
      navigate(`/search?query=${query}`)
    }
  }, [query])

  // error
  useEffect(() => {
    if (error) {
      setShowError(true)
      setTimeout(() => {
        setFadeOut(true)
        setTimeout(() => {
          setShowError(false)
        }, 1000)
      }, 5000)
    }
  }, [error])

  return (
    <div className='header'>
      <Navbar />
      <h2 className='header--heading text-center text-light'>Find Images</h2>
      <div className='header--form'>
        <form onSubmit={handleSubmit}>
          <input
            className='header--form--input'
            autoComplete='off'
            type='text'
            placeholder='Search'
            onChange={handleChange}
            name='input'
            value={query}
          />
        </form>
      </div>

      {showError && <div className={`network-error ${fadeOut ? 'fade-out' : ''}`}>
        <i><FontAwesomeIcon icon={faTriangleExclamation} /></i>
        <div className='network-error--message'>
          <h5>Network Error</h5>
          <p>Please check your Internet connection and try again</p>
        </div>
      </div>}
    </div>
  )
}

export default Header
import './App.css';
import Main from './components/Main';
import Search from './components/pages/Search'
import Favorites from './components/pages/Favorites';
import Error from './components/pages/Error';
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { SkeletonTheme } from 'react-loading-skeleton';
import { useDarkMode } from './components/Navbar';


function App() {
  const darkMode = useDarkMode(state => state.darkMode)
  let style
  if (darkMode === 'light') {
    style = 'wrapper'
  } else {
    style = 'wrapper-dark'
  }

  return (
    <div className={style}>
      <SkeletonTheme baseColor="#808080" highlightColor="#b1b1b1">
        <BrowserRouter>
          <Routes>
            <Route path='/' element={<Main />} />
            <Route path='search' element={<Search />} />
            <Route path='favorites' element={<Favorites />} />
            <Route path='*' element={<Error />} />
          </Routes>
        </BrowserRouter>
      </SkeletonTheme>
    </div>
  );
}

export default App;
mzmfm0qo

mzmfm0qo1#

如果我没理解错你的问题,你*希望在表单域更新时实时更新query queryString参数,而是在稍后的某个时候,比如表单提交时,请记住setSeaarchParams函数的工作原理与navigate函数类似,但它是对queryString进行操作的。
您可以手动更新searchParams对象,当表单提交时,调用setSearch参数而不是navigate。从input元素中删除value属性,因为我们将更新searchParams对象。

function Header() {
  ...
  const location = useLocation()
  const navigate = useNavigate();
  const [searchParams, setSearchParams] = useSearchParams()
  ...

  function handleChange(event) {
    searchParams.set("query", event.target.value);
  }

  ...

  const handleSubmit = async (event) => {
    event.preventDefault();
    fetchImages();
    setSearchParams(searchParams);
  }

  ...

  return (
    <div className='header'>
      <Navbar />
      <h2 className='header--heading text-center text-light'>Find Images</h2>
      <div className='header--form'>
        <form onSubmit={handleSubmit}>
          <input
            className='header--form--input'
            autoComplete='off'
            type='text'
            placeholder='Search'
            onChange={handleChange}
            name='input'
          />
        </form>
      </div>

      ...
    </div>
  )
}

export default Header

相关问题