zhangyuang / egg-react-ssr

最小而美的Egg + React + SSR 服务端渲染应用骨架,同时支持JS和TS
http://doc.ssr-fc.com/
MIT License
1.91k stars 211 forks source link

使用嵌套路由时,会出现含有路由组件的父组件被卸载的问题 #219

Closed hujixin1 closed 1 year ago

hujixin1 commented 1 year ago

1.问题:在某个大的父组件中,书写一个子组件,该子组件就是常规的路由组件,但通过交互触发二级路由的时候,会导致父组件被卸载;

截屏2023-08-09 12 52 17

如图,leftPanel是一个菜单组件,rightContent包含了路由组件;可以通过leftPanel修改路由,触发rightContent的某一项route,但我注意到整个Docs组件将会被卸载一次,并且导致leftPanel组件也被卸载一次,这影响了leftPanel中一些业务逻辑; 我注意到,被关闭的issue中有一个:https://github.com/zhangyuang/egg-react-ssr/issues/96, 和我的问题是一致的,作者大大关闭了它,但我还是没有找到如何解决的方法; 目前,由于业务的一些问题,不太方便迁移egg-react-ssr到作者大大最新的ssr框架,劳烦能看看怎么解决吗;

zhangyuang commented 1 year ago

使用的代码是最新的吗 https://github.com/zhangyuang/egg-react-ssr/commit/58f6f270b6bc28c9b01f15487fd5e62565219259

hujixin1 commented 1 year ago

是的,使用的是最新的代码,hoc是在render之外被调用的;

截屏2023-08-09 13 19 38

如图,当我点击左侧切换路由的时候,会触发整个大的docs组件卸载

截屏2023-08-09 13 21 19 截屏2023-08-09 13 22 09 截屏2023-08-09 13 22 16

这似乎并不是有没有在切换路由的时候,调用getInitalProps的问题,而是渲染的问题,常理说,rightContent不应该影响整个docs组件的卸载;

zhangyuang commented 1 year ago

比较难定位问题,left卸载会有什么问题呢,如果你是想要保留高亮的状态,那你应该维护一个state每次渲染组件的时候根据当前的path决定哪一块高亮

hujixin1 commented 1 year ago

leftPanel基于antd组件,该antd组件有一个defaultOpenKeys属性,可以控制哪些菜单处于展开状态(菜单指小箭头收缩那一项);

截屏2023-08-09 13 30 09

假设我目前先把菜单1收起来,把菜单二展开,在菜单二点击,触发路由的变化,菜单一不应该被重新展开,而要保持原来的状态; 但目前的问题是,切换路由,left被卸载,会再度初始化,导致他的defaultOpenKeys被重新激活,defaultOpenKeys 就是两项, 会导致菜单一也被展开; (defaultOpenKeys和form组件的initalValue属性类似,就是在挂载第一次时生效,只要组件不卸载,就算重新渲染,也不会触发了)

hujixin1 commented 1 year ago
截屏2023-08-09 13 50 49

之前那个issue的问题,下方是路由跳转,走的是客户端路由,在跳转之前可以在上方的input输入一些内容,但跳转后,只是局部切换了一些内容,却把上方的input内容清空了,这在业务里面是一种很难控制的问题,传统的cra开发的应用似乎没有这种问题,我一开始怀疑是ssr的问题,切换成csr模式,也有同样的问题,这🈶️可能是框架层面上对路由的支持的一些问题导致的

zhangyuang commented 1 year ago

在ssr框架能复现吗,能的话可以给个最小复现我看看。不过这里跳转前后两个页面的切换把input清空是正常的。前后两个页面级组件的input是不同的实例。

除非你像在Vue里面一样,把input独立出 router-view , router-view 的切换不会影响input组件

hujixin1 commented 1 year ago

1.这边的input是放在一个页面组件page组件中,下方的路由跳转是通过组件跳转的(我的理解是这个Route组件就类似于router-view),此时的page组件下方会多出一个一部分子组件的页面,但是本质上还是处于page这个页面组件下面,只是插入了一部分新的内容,所以我这里不太理解两个页面级的意思,感觉还是一个页面,作者大大;

截屏2023-08-09 14 38 30 截屏2023-08-09 14 38 35

2.ssr框架我还没有用过,如果想在egg-react-ssr里面复现这个组件卸载的问题,只需要下载一个ssr-with-js的模版,然后在index组件里面写上二级路由,并且在index组件中写上如上的useEffect,就可以看见index组件每次都被卸载,重新渲染,导致input被清空,本来input不应该被下方的Route组件影响的

zhangyuang commented 1 year ago

可以给一个可复现的ssr-with-js的 demo 仓库我今天有空看看

hujixin1 commented 1 year ago

感谢作者大大!!! https://github.com/hujixin1/hujixin

zhangyuang commented 1 year ago

你的仓库没有build文件夹

hujixin1 commented 1 year ago

抱歉作者大大,已经更新了,刚才被模版默认的gitignore拦截了build的上传,没有注意

zhangyuang commented 1 year ago
image

定位了,因为这里用了location.pathname当作key.这里可以根据具体的业务情况来调整key,比如用path当作key

hujixin1 commented 1 year ago

作者大大,我更新了github上的例子; 1.我尝试修改config.ssr.js里的route,加入了重复路由,因为/test是个非真实的地址,刷新后会出现404的问题,所以我这里重复书写了一个路由,以命中node;

截屏2023-08-09 17 09 01

2.我保持每个route的exact为true,按照之前issue上提到的,想使用嵌套路由,可以去掉一级路由上的exact,这样进行模糊匹配,二级地址也会匹配一级路由,如/docs/xx可以匹配上/docs,如果在docs组件上不设置exact=true的话,但是这样会出现一个问题,会同时匹配上两个路由,还会出现我上述说的刷新404问题; 3.我做了上述改造后,并把layout上面的key去除,还会出现我今天遇见的问题,请问大大这种要怎么处理呢

zhangyuang commented 1 year ago

那你在controller添加对应的path的处理逻辑

hujixin1 commented 1 year ago

这里不太明白怎么做特化处理,作者大大方便再看看我新更新的那个例子吗,可以看看为啥会出现卸载吗,这点我觉得目前比较困惑

zhangyuang commented 1 year ago

刷新404的问题通过controller去解决,跟exact没关系

hujixin1 commented 1 year ago

controller中,我尝试用正则去匹配,避免出现404;

截屏2023-08-09 20 22 07

但是在前端会出现这个报错,

截屏2023-08-09 20 23 46

这个报错的来由不是很明确,为什么两方的比对结果会不同,我仅仅是想把/docs/xx这样的路径都打到/docs的路由上呀

zhangyuang commented 1 year ago

/doc/*, 需要页面渲染的请求在这里能接收到就行了。这些都是纯业务问题