提取后重定向到结果页面

Redirect after fetch to results page

提问人:Katharina Schreiber 提问时间:11/12/2023 最后编辑:Robin ThomasKatharina Schreiber 更新时间:11/13/2023 访问量:26

问:

我在next.js App的索引页面上有一个searchBar组件:

type WeatherData = {
  location: {
    name: string;
  };
  current: {
    temp_c: number;
  };
};

const SearchBar = ({
  setSearchData
}: {
  setSearchData: React.Dispatch<React.SetStateAction<WeatherData | null>>;
}) => {
  const router = useRouter()
  const [searchTerm, setSearchTerm] = useState('')

  // If there was a "real" API search term would be needed for request too
  const handleSearch = async (e: React.FormEvent) => {
    e.preventDefault()

    const apiUrl = 'http://api.weatherapi.com/v1/current.json?key=';
    const apiKey = '*************';

    const url = `${apiUrl}${apiKey}&q=${encodeURIComponent(searchTerm)}&aqi=no`;
    try {
      const searchData: WeatherData = await fetchData(url);
      
      console.log('Weather object:', searchData);
      
      setSearchData(searchData);
      // Redirect to search results page
      const searchResultUrl = `/searchResults?q=${encodeURIComponent(
        searchTerm,
      )}&p=1`
      router.push(searchResultUrl)
    } catch (error) {
      console.error('Error fetching search results:', error)
    }
  }

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setSearchTerm(e.target.value)
  }

  return (
    <form onSubmit={handleSearch} className="flex">
      <label htmlFor="search-bar" className="sr-only">
        Search statista
      </label>
      <input
        id="search-bar"
        name="search"
        type="search"
        required
        value={searchTerm}
        onChange={handleChange}
        className="h-14 md:w-[500px] sm:w-full rounded-l-md border-2 border-skyblue bg-white px-3.5 py-2 text-gray-900 focus:outline-none"
        placeholder="Find statistics, forecasts and reports"
      />
      {/* area label here isn't really  needed as the button already has it's content*/}
      <button
        type="submit"
        className="h-14 md:w-[200px] rounded-r-md bg-skyblue border-2 border-skyblue text-white font-bold py-2 px-4 focus:outline-none flex items-center justify-center"
        aria-label="Search"
      >
      {/* svg typically needs title and description and aria-labledby, referring to the title. Maybe use role graphics-symbol as it is an icon*/}
        <span className="hidden md:inline mr-2 font-sans">Statista search</span>
        <svg
          width="14"
          height="14"
          viewBox="0 0 14 14"
          fill="none"
          xmlns="http://www.w3.org/2000/svg"
          role="img"
          aria-labelledby="search-icon"
        >
          <title id="search-icon">Search Icon</title>
          <path
            fillRule="evenodd"
            clipRule="evenodd"
            d="M0 5.83335C0 7.38044 0.614573 8.86418 1.70854 9.9581C2.80249 11.0521 4.28621 11.6667 5.8333 11.6667C6.98558 11.6667 8.10271 11.3258 9.04983 10.6998L12.0084 13.6583C12.464 14.1139 13.2027 14.1139 13.6583 13.6583C14.1139 13.2027 14.1139 12.464 13.6583 12.0084L10.6997 9.04982C11.3257 8.10272 11.6666 6.98561 11.6666 5.83335C11.6666 4.28625 11.052 2.80251 9.95802 1.70855C8.8641 0.614578 7.38038 0 5.8333 0C4.28621 0 2.80249 0.614578 1.70854 1.70855C0.614573 2.80251 0 4.28625 0 5.83335ZM3.35844 8.30822C2.70207 7.65184 2.33332 6.76161 2.33332 5.83335C2.33332 4.90509 2.70207 4.01485 3.35844 3.35847C4.01481 2.70209 4.90504 2.33334 5.8333 2.33334C6.76155 2.33334 7.65178 2.70209 8.30815 3.35847C8.96453 4.01485 9.33327 4.90509 9.33327 5.83335C9.33327 6.76161 8.96453 7.65184 8.30815 8.30822C7.65178 8.9646 6.76155 9.33335 5.8333 9.33335C4.90504 9.33335 4.01481 8.9646 3.35844 8.30822Z"
            fill="white"
          />
        </svg>
      </button>
    </form>
  );
};

export default SearchBar

所以正如你所看到的,我的searchBar重定向到searchResults页面:

type WeatherData = {
  location: {
    name: string;
  };
  current: {
    temp_c: number;
  };
};

const SearchResults = () => {
  const [searchData, setSearchData] = useState<WeatherData | null>(null);
  const [currentPage, setCurrentPage] = useState(1)
  const [itemsPerPage, setItemsPerPage] = useState(10)
  const searchParams = useSearchParams()
  const searchTerm = searchParams.get('q')
  // get to a desired page by changing url params
  const requestedPage = searchParams.get('p')

  // get to a desired page by changing url params
  useEffect(() => {
    if (requestedPage) {
      setCurrentPage(parseInt(requestedPage, 10))
    }
  }, [requestedPage])

  // Calculate number of pages for pagination
  // const totalPages = Math.ceil(searchData?.length / itemsPerPage)

  // Get current items for pagination
  const indexOfLastItem = currentPage * itemsPerPage
  const indexOfFirstItem = indexOfLastItem - itemsPerPage
  //const currentItems = searchData.slice(indexOfFirstItem, indexOfLastItem)
  console.log(searchData)
  return (
    <>
      <div className="bg-royalblue md:px-100 h-[150px]">
        <div className="pt-10">
          <Image
            src="statista_logo.svg"
            alt="Statista Logo"
            width={200}
            height={50}
            className="lg:absolute top-10 left-40 mx-auto"
          />
        </div>
      </div>
      <div className="h-[100px] flex items-center justify-center px-10 bg-white">
        <SearchBar setSearchData={setSearchData} />
      </div>
      <div role="status" aria-live="polite" className="h-[100px] bg-lightgrey lg:px-40 px-10 font-sans py-7">
        {/* <h2 className="text-spacegray font-bold" aria-label={`Total results: ${searchData.length}`}>
          TOTAL RESULTS: <span className="text-royalblue font-thin">{searchData.length}</span>
        </h2> */}
        <h2 className="text-spacegray font-bold" aria-label={`Search term: ${searchTerm}`}>
          SEARCH TERM: <span className="text-royalblue font-thin">{searchTerm}</span>
        </h2>
      </div>
      {searchData ? (
        <div className="lg:px-40 px-10 bg-white py-10">
          <div className="space-y-4 bg-white">
            <div className="text-skyblue font-bold font-sans">
              {searchData.location.name}
            </div>
            <div className="text-royalblue overflow-ellipsis overflow-hidden whitespace-nowrap font-sans font-thin">
              {searchData.current.temp_c}
            </div>
          </div>
            
          
          <div className="px-48 bg-white py-10">
            <Pagination
              currentPage={currentPage}
              totalPages={20}
              setCurrentPage={setCurrentPage}
            />
          </div>
        </div>
      ) : (
        <p>No search results yet.</p>
      )}
    </>
  )
}

export default SearchResults

然而,我的 searchData 在初始加载时为 null,如果我在 searchResult 页面上使用 searchBar,则 searchData 会正确加载。我已经搜索了一段时间,我得到的唯一简单的解决方案是再次(或者可能只是)在 searchResults 页面上获取。还有其他方法可以获取数据并将其从 searchBar 传递到 searchResults,包括初始加载?标准是什么?去哪里取?

reactjs next.js fetch

评论


答: 暂无答案