index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
App.js文件
import { HashRouter, Routes, Route } from 'react-router-dom';
import Login from './page/login'
import Loginafter from './page/login/loginafter';
import Loginbefore from './page/login/loginbefore';
import Home from './page/home/home'
import About from './page/about/about'
import Integrated from './page/integrated/integrated'
import Sidebar from './page/sidebar/sidebar'
import Latent from './page/latent/latent'
import Particulars from './page/particulars/particulars'
import SecurityCheck from './page/securityCheck/securityCheck'
function App() {
{/* 如果需要默认显示页面将不需要填写路径 ,子路由不需要写/斜杠跳转时会带有*/}
return (
<HashRouter>
<Routes>
<Route path='/' element={<Login />} >
<Route path='' element={<Loginbefore />} ></Route>
<Route path='/Loginafter' element={<Loginafter />} ></Route>
</Route>
<Route path='/home' element={<Home />} ></Route>
<Route path='/about' element={<About />} >
<Route path='' element={<Integrated />} ></Route>
<Route path='sidebar' element={<Sidebar />} >
<Route path='' element={<Latent />} ></Route>
<Route path='particulars' element={<Particulars />} ></Route>
<Route path='securityCheck' element={<SecurityCheck />} ></Route>
</Route>
</Route>
</Routes>
</HashRouter>
);
} export default App;

关于使用 outlet 会令prop无法准确的传达到子组件,提供案例如下

父组件案例【about.js】
import React from 'react';
import { Outlet, useNavigate } from 'react-router-dom'; export default function About() {
const navigate = useNavigate();
// let ddd = [{ sss: 2 }, { bbb: 4 }]
let ddd = 1;
const [count, setCount] = React.useState(ddd); //子组件对 setCount 操作后将被此处响应接收
return (
<>
{/* 跳转的同时 重定向默认页 */}
{/* navigate('integrated', {replace: true}); */} {/* 跳转默认页 */}
{/* navigate('',); */} {/* 变更父页 '/'+页名 */}
{/* navigate('/home') */} {/* 跳转同级页 页名 */}
{/* navigate('sidebar') */} {/* 跳转子页面 页名+'/子页名' */}
{/* navigate('sidebar/securityCheck', { state: ddd }); */}
{/* 实验,页面跳转时传入的参数,会不会随着刷新丢失? */}
{/* 结论: 依旧建议数据为接口返回的,当然,接收页(子组件)收到的数据并不会被刷新掉 */} {/* 回到上一页 */}
{/* navigate(-1) */}
<div>
<h4>About</h4>
<button onClick={() => {
navigate('test', { state: ddd });
// state 传参不限制传参类型
}}>点击Test页</button>
</div> {/* 以下为渲染子页面 */}
<Outlet context={[count, setCount]} />
</>
)
}
子组件案例【test.js】
import React, { Component } from 'react'
import { useOutletContext } from 'react-router-dom';
// outlet 状态共享
// 无状态子组件自身发生数据变化,同步给outlet上游组件 本文件以此实现数据共享
const Test = () => {
const [count, setCount] = useOutletContext();
console.log('count',count) //打印父数据
//useOutletContext 路由内置方法,监听数据发生变动
//数据类型任意 由上游 父组件决定
const increment = () => setCount((c) => c + 1); //操作父数据
return <button onClick={increment}>{count}</button>;
}
export default Test

在outlet实际摸索中,我的子组件对一则对象的某字段数据进行变更,他发生了报错。


即使outlet 共享了数据/状态,子组件初次渲染也拿到了,但超出局面的状况,可能是由于我有部分知识未能掌握,又或者由其他原因造成的。


查阅了网上一些博主的做法后,我尝试了使用 useEffect 异步更新,然并软。


this.forceUpdate() 强制更新,毕竟我实操变更后数据后,父组件成功打印了它。


然并软。(我猜测可能是子组件为无状态组件缘故,无生命周期导致数据变更的第一时间发生了请求...可以尝试用构造类组件写,当然useOutletContext只支持无状态组件内使用...)


有位博主的做法是,判定虚拟dom元素创建前,获取路由路径,这种做法挺高明的,我也是打算用一则案例写跳转时token的判定机制,和他的这种殊道同归,他也是以一种上下文的实现途径,只不过我是以v6的那种,他的写法上配置全局上下文,有点费时间,早期写过但版本不一致导致我这边报错过,所以我舍弃了旧写法。
但我依旧认为,一定有种很简别的方式实现数据变更,也许只是我没有想到而已...


最终,有一则报错告诉我,我可能需要将数据以数组包对象形式传递给子组件。


于是,我猜测,当我编辑后返回数据时,我可能需要push进去,再删除编辑前的数据,使我的无状态组件渲染时,不至于某行字段报null 或undefined。
至此,附上新案例:

父组件 login 文件夹下的 index.js
import React, { Component, useEffect } from 'react'
import { Outlet, useNavigate, useSearchParams } from 'react-router-dom'; const Btn = () => {
let state = {
token: 'asldfjdljfdsojdakf haiksf',
userName: 'zhangsan',
password: '123456'
} // let state = 11
const [grossdata, setgrossdata] = React.useState([state]) // useEffect(() => {
// console.log('异步更新', grossdata)//监听数据发生了更改
// console.log('this',this)
// // this.forceUpdate()
// // if (!grossdata.token) {
// // console.log('判断')
// // // grossdata.token = <></>
// // // this.forceUpdate()
// // }
// }, [grossdata]) const navigate = useNavigate(); return <>
<button onClick={() => { navigate('Loginafter') }}>前往登录后</button>
<Outlet context={[grossdata, setgrossdata]} />
</>
} export class index extends Component {
render() {
return (
<>
<h4>这是管理登录页和登录后页面的文件</h4>
<Btn></Btn>
</>
)
}
} export default index
子组件 login 文件夹下的 loginafter.js
import React from 'react'
import { useOutletContext } from 'react-router-dom'; const Loginafter = () => {
const [grossdata, setgrossdata] = useOutletContext();
console.log('grossdata子组件打印', grossdata)
const increment = () => setgrossdata((c) => {
c[0].token = '';
let f = c[0]
return c.push(f) && c.splice(0, 1)
}); //操作父数据 return <>
<div>登录后</div>
<button onClick={increment}>清除token</button>
<br></br>
<span>{grossdata[0].token} </span>
<br></br>
<span>{grossdata[0].userName}</span>
<br></br>
<span>{grossdata[0].password}</span>
</>
}
export default Loginafter

我决定尝试,outlet 默认子组件操作 父组件事件...


补充:


对 useOutletContext 接收的数据,我起初只想着用,但在为对象做变更时报错,以致发现自己的无知,这使我做了许多无用功:this.forceUpdate() 强制更新, useEffect 异步更新 。


瞅下官网的说法:

官网原文链接: https://react.dev/learn/updating-objects-in-state

React学习时,outlet 路由配置 (prop传参处理,跳转的实现,父子数据共享)的更多相关文章

  1. Tornado学习笔记(二) 路由/post/get传参

    本章我们学习 Tornado 的路由传参等问题 路由 路由的匹配 Tornado的路由匹配采用的是正则匹配 一般情况下不需要多复杂的正则,正则的基本规则如下(站长之家) 举个例子 (r'/sum/(\ ...

  2. Angular:路由的配置、传参以及跳转

    ①路由的配置 1.首先用脚手架新建一个项目,在路由配置时选择yes 2.用ng g component创建组件 3.在src/app/app-routing.module.ts中配置路由 import ...

  3. Nuxt的路由配置以及传参

    Nuxt 路由可以使用a标签进行链接跳转,例如我们创建了一个demo.vue的文件 <p> <a href="/demo">跳转去Demo页面</a& ...

  4. vue路由对不同界面进行传参及跳转的总结

    最近在做一个公众号的商城项目,主要用的VUE+MUI,其实今天这个点对于有过项目经验的前端工作者来说是最基础的,但也是必须要掌握的,今天小编主要是记录下传参和跳转的一些总结(仅供参考). 首先我们先上 ...

  5. Vue Router路由导航及传参方式

    路由导航及传参方式 一.两种导航方式 ①:声明式导航 <router-link :to="..."> ②:编程式导航 router.push(...) 二.编程式导航参 ...

  6. vue学习(6)-路由(导入包;创建子组件;创建路由对象)传参,子路由,多个组件

    后端路由:对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源 前端路由:对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换(不会刷新页 ...

  7. vue2.0路由写法、传参和嵌套

    前置知识请戳这里 vue-routerCDN地址:https://unpkg.com/vue-router@3.0.1/dist/vue-router.js vue-router下载地址:https: ...

  8. ionic简单路由及页面传参

    1)页面跳转及传参方法 angular.module('app.routes', [])//routes路由模型 .config(function($stateProvider, $urlRouter ...

  9. vue路由传参并跳转页面

    在vue项目中参数的传递可以使用本地缓存或者Vuex,那么vue能不能像小程序一样路由传参呢,显然是可以的而且非常简单 方式一:query传参 //传参 go(){ that.$router.push ...

  10. vue-router路由如何实现传参

    tip: 用params传参,F5强制刷新参数会被清空,用query,由于参数适用路径传参的所以F5强制刷新也不会被清空.(传参强烈建议适用string) 也可以选用sessionstorage/lo ...

随机推荐

  1. pandas之缺失值处理

    在一些数据分析业务中,数据缺失是我们经常遇见的问题,缺失值会导致数据质量的下降,从而影响模型预测的准确性,这对于机器学习和数据挖掘影响尤为严重.因此妥善的处理缺失值能够使模型预测更为准确和有效. 为什 ...

  2. matplotlab可视化学习

    1 使用pip安装 使用 Python 包管理器 pip 来安装 Matplotlib 是一种最轻量级的方式.打开 CMD 命令提示符窗口,并输入以下命令: pip install matplotli ...

  3. [Python]Python安装教程

    anaconda Anaconda:python的一种软件发行版.Anaconda发行版会预装很多pydata生态圈里的软件,而Miniconda是最小的conda安装环境, 一个干净的conda环境 ...

  4. [数据库]MySQL解决:MySQLNonTransientConnectionException: Could not create connection to database server.【待完善】

    场景复现 mysql数据库 5.7.24 jdbc driver: mysql-connector-java: 5.1.33 jdbc 配置: + jdbc.url + driverName: Tom ...

  5. C# 通过一个控制台打开另一个控制台

    现有个需求是通过一个主程序获取配置的线程数和进程数打开连一个控制台程序,将线程数和系统编码作为参数传给控制台程序. 下面附上Demo. 1 private static void Main(strin ...

  6. redhat6安装10g rac过程中的报错

    问题描述:redhat 6 来安装oracle10.2.0.1的集群,坑太多了,不建议这样安装,即使安装成功,在升级过程中也会有各种报错.redhat5安装还比较顺利,6就一路坑 1.缺少依赖 lib ...

  7. QUIC协议 对比 TCP/UDP 协议

    QUIC协议是HTTP3引入的,所以需要了解HTTP的版本迭代. HTTP1.x 队头阻塞:下个请求必须在前一个请求返回后才能发出,导致带宽无法被充分利用,后续请求被阻塞(HTTP 1.1 尝试使用流 ...

  8. 重新实现hashCode()方法

    在Java中,为了让对象在集合中能够更高效地进行查找和比较,我们通常需要重写对象的equals()和hashCode()方法.其中,equals()方法用于比较两个对象是否相等,而hashCode() ...

  9. 使用js截取路径参数方法

    1.根据传入的路径和参数名称截取 export function getUrlParams(href,name) { var reg = new RegExp("(^|\\?|&)& ...

  10. Win HttpRunner3 + Allure 实现接口自动化

    HTTPRunner3介绍: HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON 脚本,即可实现自动化测试.性能测试.线上监控.持续集成等多种测 ...