我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

ReactRouterstate,除了可以使用LinkNavLink来传递外,还可以使用useNavigate()钩子进行处理。H5原生的state则是可以通过history对象进行编程处理。(ReactRouter@v5版本里面,还是使用useHistory()钩子进行处理的)那么,两者之间的state存在着什么样的联系呢?可否通过相互设置进行内容修改呢?本文来试图找出其中的因果联系。

苏南大叔:React路由的state和H5原生state,如何相互设置和读取? - 路由state和原生state
React路由的state和H5原生state,如何相互设置和读取?(图6-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0create-react-app@5.0.1react-router-dom@6.27.0react@18.3.1

前文回顾

state对象依存于location对象,location对象对应着URL的变化。使用了ReactRouterReact项目,有着自己的URL,它可以和浏览器地址栏里面的地址,一致或者不一致。

本文源码基于create-react-appcra模版。可以使用下面的命令,获得基础代码框架。

create-react-app test
cd test
npm i react-router-dom --save

纯原生监控state

本段代码是纯原生情况下的state监控代码,参考文章:

苏南大叔:React路由的state和H5原生state,如何相互设置和读取? - 整体state
React路由的state和H5原生state,如何相互设置和读取?(图6-2)

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;

苏南大叔:React路由的state和H5原生state,如何相互设置和读取? - 局部react检测state
React路由的state和H5原生state,如何相互设置和读取?(图6-3)

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()进行操作。获得了ReactRouterstate记录,整体页面上通过对state事件监控,获得state的值。

读取state

局部React程序的state,使用下面的方式读取:

const { pathname,state } = useLocation();

整体页面的state,使用下面的方式读取:

window.location.state

state事件中,使用下面的方式读取:

("state" in event)?event.state:event.detail?.state

两个state的联系性

ReactRouterstate,举例:

{"id":0,"from":"JavaScript"}

页面原生的state,举例:

{"usr":{"id":0,"from":"JavaScript"},"key":"hitn4box","idx":2}

所以,ReactRouter实际表现出来的state,只是其原生state值的一部分。

局部整体相互影响

React部分中,任何的state改变,对原生的state都有影响。

苏南大叔:React路由的state和H5原生state,如何相互设置和读取? - 局部影响全局
React路由的state和H5原生state,如何相互设置和读取?(图6-4)

而反过来,原生state变化的时候,pushreplace目前对react版的state没影响。其它情况下,有影响也需要具有正确的格式。

苏南大叔:React路由的state和H5原生state,如何相互设置和读取? - 全局不一定影响局部
React路由的state和H5原生state,如何相互设置和读取?(图6-5)

其它结论

这里是本次实验得出的额外结论,和主体内容关系不大。

  • 原生state有初始值,内容是{"idx":0};
  • ReactuseLocation(),不响应全局页面的pushStatereplaceState。但是响应全局的history.back()history.forward(),也就是浏览器的前进和后退按钮。
  • 全局的state如果符合react的特殊格式,也可以反向作用于react程序。

苏南大叔:React路由的state和H5原生state,如何相互设置和读取? - 前进后退的时候一定同步
React路由的state和H5原生state,如何相互设置和读取?(图6-6)

结论

结论就是,两者之间确实存在关联。相互设置和读取,也存在着可能性。虽然两者的state并不完全一致,但是有套路可循。
更多苏南大叔的React经验文章,请点击苏南大叔的博客:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   react