React路由的state和H5原生state,如何相互设置和读取?
发布于 作者:苏南大叔 来源:程序如此灵动~ReactRouter
的state
,除了可以使用Link
或NavLink
来传递外,还可以使用useNavigate()
钩子进行处理。H5
原生的state
则是可以通过history
对象进行编程处理。(ReactRouter@v5
版本里面,还是使用useHistory()
钩子进行处理的)那么,两者之间的state
存在着什么样的联系呢?可否通过相互设置进行内容修改呢?本文来试图找出其中的因果联系。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0
,create-react-app@5.0.1
,react-router-dom@6.27.0
,react@18.3.1
。
前文回顾
state
对象依存于location
对象,location
对象对应着URL
的变化。使用了ReactRouter
的React
项目,有着自己的URL
,它可以和浏览器地址栏里面的地址,一致或者不一致。
- https://newsn.net/say/react-link-state.html
- https://newsn.net/say/h5-state.html
- https://newsn.net/say/react-location.html
本文源码基于create-react-app
的cra
模版。可以使用下面的命令,获得基础代码框架。
create-react-app test
cd test
npm i react-router-dom --save
纯原生监控state
本段代码是纯原生情况下的state
监控代码,参考文章:
public/index.html
:
<style>
a {
margin: 0px 5px;
}
.root {
width: 460px;
border: 1px solid red;
margin: 5px;
float: left;
clear: both;
}
</style>
<div class="root">
<div class="bar">
<button onClick="javascript:doPush()">push</button>
<button onClick="javascript:doPush2()">push2</button>
<button onClick="javascript:doReplace()">replace</button>
<button onClick="javascript:doPop()">back</button>
<button onClick="javascript:doForward()">forward</button>
</div>
<div id="info"></div>
</div>
<script>
(function (history) {
var pushState = history.pushState;
history.pushState = function (state, title, url) {
var result = pushState.apply(history, arguments);
var event = new CustomEvent("pushstate", {
detail: { state: state, title: title, url: url },
});
window.dispatchEvent(event);
return result;
};
var replaceState = history.replaceState;
history.replaceState = function (state, title, url) {
var result = replaceState.apply(history, arguments);
var event = new CustomEvent("replacestate", {
detail: { state: state, title: title, url: url },
});
window.dispatchEvent(event);
return result;
};
})(window.history);
const navHandle = (event) => {
var a = window.location.pathname;
// var b = "state" in event ? event.state : event.detail?.state;
var b = window.history.state;
b = JSON.stringify(b);
document.getElementById("info").innerHTML = [a, b].join("<br/>");
};
navHandle();
window.addEventListener("pushstate", navHandle);
window.addEventListener("popstate", navHandle);
window.addEventListener("replacestate", navHandle);
function doPop() {
window.history.back();
}
function doForward() {
window.history.forward();
}
function doPush() {
window.history.pushState(
{ usr: { id: 4, from: "push" }, key: "klx27dkq", idx: 1 },
"title",
"/s"
);
}
function doPush2() {
window.history.pushState(
{ usr: { id: 5, from: "push2" }, key: "3o8t6e7s", idx: 1 },
"title",
"/n"
);
}
function doReplace() {
window.history.replaceState(
{ usr: { id: 6, from: "replace" }, key: "46uxwxhl", idx: 1 },
"title2",
"/n"
);
}
</script>
React监控state
当然,这里指的是ReactRouter
下的state
监控。参考文章:
src/App.js
:
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Layout from "./Layout";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout></Layout>}>
<Route path="/s" element={<></>}></Route>
<Route path="/n" element={<></>}></Route>
</Route>
</Routes>
</BrowserRouter>
);
}
export default App;
src/Layout.js
:
import { Link, NavLink, Outlet } from "react-router-dom";
import { useNavigate, useLocation } from "react-router-dom";
const Layout = () => {
// 接受 state
const { pathname, state } = useLocation();
// 发送 state
let navigate = useNavigate();
function doPush(e) {
navigate("/", { state: { id: 0, from: "js push" } });
}
function doReplace(e) {
navigate("/", { state: { id: 1, from: "js replace" },replace:true });
}
function doBack(e) {
navigate(-1);
}
function doForward(e) {
navigate(1);
}
return (
<>
<div className="bar">
<button onClick={doPush}>函数Push</button>
<Link to="/s" state={{ id: 1, from: "Link" }}>
Link
</Link>
<NavLink to="/n" state={{ id: 2, from: "NavLink" }}>
NavLink
</NavLink>
<button onClick={doReplace}>函数Replace</button>
<button onClick={doBack}>函数Back</button>
<button onClick={doForward}>函数Forward</button>
</div>
{pathname}
<br />
{JSON.stringify(state)}
<br />
{state?.id},{state?.from}
<Outlet></Outlet>
</>
);
};
export default Layout;
局部React
里面,通过对Link
/NavLink
/useNavigate()
进行操作。获得了ReactRouter
的state
记录,整体页面上通过对state
事件监控,获得state
的值。
读取state
局部React
程序的state
,使用下面的方式读取:
const { pathname,state } = useLocation();
整体页面的state
,使用下面的方式读取:
window.location.state
state
事件中,使用下面的方式读取:
("state" in event)?event.state:event.detail?.state
两个state的联系性
ReactRouter
的state
,举例:
{"id":0,"from":"JavaScript"}
页面原生的state
,举例:
{"usr":{"id":0,"from":"JavaScript"},"key":"hitn4box","idx":2}
所以,ReactRouter
实际表现出来的state
,只是其原生state
值的一部分。
局部整体相互影响
在React
部分中,任何的state
改变,对原生的state
都有影响。
而反过来,原生state
变化的时候,push
和replace
目前对react
版的state
没影响。其它情况下,有影响也需要具有正确的格式。
其它结论
这里是本次实验得出的额外结论,和主体内容关系不大。
- 原生
state
有初始值,内容是{"idx":0}
; React
的useLocation()
,不响应全局页面的pushState
和replaceState
。但是响应全局的history.back()
和history.forward()
,也就是浏览器的前进和后退按钮。- 全局的
state
如果符合react
的特殊格式,也可以反向作用于react
程序。
结论
结论就是,两者之间确实存在关联。相互设置和读取,也存在着可能性。虽然两者的state
并不完全一致,但是有套路可循。
更多苏南大叔的React
经验文章,请点击苏南大叔的博客:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。