ReactJS:表单提交后无刷新跳转及搜索结果持久化问题
解决你的React路由跳转和状态持久化问题
我来帮你搞定这两个头疼的问题,咱们一步步拆解:
一、解决无刷新跳转路由的问题
你现在的写法里,把<Link>嵌套在提交按钮里,这会导致点击按钮时直接触发路由跳转,而你的异步搜索请求还没完成,这就导致跳转后可能拿不到最新的搜索结果。而且这种写法本身就不符合React Router的使用逻辑。
修改方案:
- 因为你的组件已经用
withRouter包裹了,所以可以直接从props里拿到history对象,用来手动跳转路由。 - 移除按钮里的
<Link>标签,让按钮只负责触发表单提交。 - 在
submitSearch函数中,当成功获取到搜索结果并更新状态后,调用history.push()跳转到结果页面。
修改后的Search组件代码(标注了修改点):
import React, { Fragment, useState, useEffect, useContext } from "react"; import { withRouter } from "react-router-dom"; import searchResultContext from "./SearchResultContext"; // 接收props以获取history对象 const Search = (props) => { const [wave, setWave] = useState("$perc"); const [pack_hu, setPackHu] = useState("$perc"); const { searchResult, setSearchResult } = useContext(searchResultContext); // 从props解构出history const { history } = props; useEffect(() => { console.log(JSON.stringify(searchResult)); }, [searchResult]); //submit a form to search const submitSearch = async (e) => { e.preventDefault() try { const response = await fetch( `http://localhost:5000/yourstage/search/${wave}/${pack_hu}`, { method: "GET", headers: { "Content-Type": "application/json" }, } ); const resultData = await response.json(); setSearchResult(resultData); // 搜索成功后手动触发路由跳转 history.push('/yourstage/results'); //Reset Form and State document.getElementById("searchForm").reset(); setWave("$perc"); setPackHu("$perc"); } catch (error) { console.error(error.message); } }; //return the form html return ( <Fragment> <h1 className="text-center mt-3">Search</h1> <form id="searchForm" onSubmit={submitSearch}> <div className="form-group row"> <label htmlFor="Wave" className="col-sm-2 col-form-label"> Wave: </label> <div className="col-sm-10"> <input type="text" className="form-control" placeholder="Wave Number" maxLength="10" onChange={(e) => setWave(e.target.value)} /> </div> </div> <div className="form-group row"> <label htmlFor="pack_hu" className="col-sm-2 col-form-label"> Pack HU: </label> <div className="col-sm-10"> <input type="text" className="form-control" placeholder="Pack HU" maxLength="10" onChange={(e) => setPackHu(e.target.value)} /> </div> </div> <div className="row text-center mt-5"> <div className="col-6"> {/* 移除嵌套的Link,仅保留提交按钮 */} <button type="submit" className="btn-lg btn-primary"> Search </button> </div> </div> </form> </Fragment> ); }; export default withRouter(Search);
二、解决页面刷新后searchResult丢失的问题
React Context的状态是存储在内存中的,当页面刷新时,整个React应用会重新初始化,内存里的状态自然就丢失了。要解决这个问题,我们需要把搜索结果持久化到本地存储(比如localStorage),这样刷新页面后可以从本地存储中恢复数据。
修改方案:
- 在设置
searchResult状态的同时,把数据存入localStorage。 - 在你的
SearchResultContext的Provider组件中,初始化状态时优先从localStorage读取数据,如果没有则用默认值。
第一步:修改submitSearch函数,存储数据到localStorage
在之前的submitSearch里,更新状态的时候加上本地存储的逻辑:
const resultData = await response.json(); setSearchResult(resultData); // 将结果存入localStorage(注意转成JSON字符串) localStorage.setItem('searchResult', JSON.stringify(resultData));
第二步:修改Context Provider的初始化逻辑
假设你的SearchResultContext的Provider代码如下,修改初始化状态的部分:
import React, { useState, createContext } from 'react'; const searchResultContext = createContext(); export const SearchResultProvider = ({ children }) => { // 从localStorage读取初始值,没有的话用空数组/对象(根据你的数据结构调整) const [searchResult, setSearchResult] = useState( JSON.parse(localStorage.getItem('searchResult')) || [] ); return ( <searchResultContext.Provider value={{ searchResult, setSearchResult }}> {children} </searchResultContext.Provider> ); }; export default searchResultContext;
可选优化:
如果希望用户关闭浏览器后数据自动清除,可以用sessionStorage代替localStorage,用法完全一样,只是存储的有效期不同。
最后验证一下
现在你点击搜索按钮,会先完成异步请求,把结果存入Context和本地存储,然后无刷新跳转到结果页面;即使刷新结果页面,也会从本地存储中读取之前的搜索结果,不会丢失数据啦~
内容的提问来源于stack exchange,提问作者John Jam
相关产品推荐
相关产品推荐

