Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

子路由切换导致 layout 组件卸载重新渲染 #6980

Closed
apathyjade opened this issue Aug 30, 2024 · 11 comments
Closed

子路由切换导致 layout 组件卸载重新渲染 #6980

apathyjade opened this issue Aug 30, 2024 · 11 comments

Comments

@apathyjade
Copy link

apathyjade commented Aug 30, 2024

说明
/page/layout.tsx
/page/a.tsx
/page/b.tsx
在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;

[ice/packages/runtime/src
/ClientRouter.tsx](https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)

`

if (process.env.ICE_CORE_ROUTER === 'true') {
// Clear router before re-create in case of hot module replacement.
clearRouter();
// @ts-expect-error routes type should be AgnosticBaseRouteObject[]
router = createRouter(routerContext).initialize();
disableHistoryWarning();
// Replace history methods by router navigate for backwards compatibility.
setHistory(createRouterHistory({ ...routerContext.history }, router));
}

`
每次切换路由时 触发更新ClientRouter 导致router重新创建;

https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx
`

// 614row
React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);

// 739 row
{state.initialized || router.future.v7_partialHydration ? (

) : (
fallbackElement
)}

`
state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

@lhb2631225005
Copy link

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;

[ice/packages/runtime/src /ClientRouter.tsx](https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)

`

if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); }

` 每次切换路由时 触发更新ClientRouter 导致router重新创建;

https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx `

// 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]);

// 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )}

` state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

@apathyjade
Copy link
Author

apathyjade commented Sep 2, 2024

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx](https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx](https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

你的问题可以通过调整 绑定事件的节点 或者 触发的时间节点绕过过去

@lhb2631225005
Copy link

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx](https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)[ ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx](https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

你的问题可以通过调整 绑定事件的节点 或者 触发的时间节点绕过过去

我是在layout的useEffect里面给window注册了message事件 我需要在详情页回到列表页的时候通知刷新或者不刷新 但是在我进入详情页的时候 这个事件被注销了 所以我详情页回到列表页的时候 监听不到消息
我目前的解决方案是在发送消息的时候 套一个setTimeout 让它变成宏任务 这样它可以在layout注册事件后触发 这样是可以监听到的

@apathyjade
Copy link
Author

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx](https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

你的问题可以通过调整 绑定事件的节点 或者 触发的时间节点绕过过去

我是在layout的useEffect里面给window注册了message事件 我需要在详情页回到列表页的时候通知刷新或者不刷新 但是在我进入详情页的时候 这个事件被注销了 所以我详情页回到列表页的时候 监听不到消息 我目前的解决方案是在发送消息的时候 套一个setTimeout 让它变成宏任务 这样它可以在layout注册事件后触发 这样是可以监听到的

可以使用 useLayoutEffect 绑定事件

@ClarkXia
Copy link
Collaborator

ClarkXia commented Sep 4, 2024

@apathyjade 可以直接提供下 layout 的相关代码

@lhb2631225005
Copy link

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx](https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

你的问题可以通过调整 绑定事件的节点 或者 触发的时间节点绕过过去

我是在layout的useEffect里面给window注册了message事件 我需要在详情页回到列表页的时候通知刷新或者不刷新 但是在我进入详情页的时候 这个事件被注销了 所以我详情页回到列表页的时候 监听不到消息 我目前的解决方案是在发送消息的时候 套一个setTimeout 让它变成宏任务 这样它可以在layout注册事件后触发 这样是可以监听到的

可以使用 useLayoutEffect 绑定事件

是的 换成 useLayoutEffect 绑定事件是可以的 感谢

@lhb2631225005
Copy link

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)[ ice/ packages/ runtime/ src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx](https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)[ ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

你的问题可以通过调整 绑定事件的节点 或者 触发的时间节点绕过过去

我是在layout的useEffect里面给window注册了message事件 我需要在详情页回到列表页的时候通知刷新或者不刷新 但是在我进入详情页的时候 这个事件被注销了 所以我详情页回到列表页的时候 监听不到消息 我目前的解决方案是在发送消息的时候 套一个setTimeout 让它变成宏任务 这样它可以在layout注册事件后触发 这样是可以监听到的

可以使用 useLayoutEffect 绑定事件

是的 换成 useLayoutEffect 绑定事件是可以的 感谢

@apathyjade useLayoutEffect 有几率不生效(发送消息后才执行注册事件)

@apathyjade
Copy link
Author

apathyjade commented Sep 6, 2024

@apathyjade 可以直接提供下 layout 的相关代码

import {  useEffect } from 'react';

import { Outlet } from 'ice';

const PageLayout = () => {
  useEffect(() => {
    console.log('切换子路由');
  }, [])
  return <Outlet />
}; 

export default PageLayout;

最基础的一个layou.tsx; 正常来说 在当前模版下的子路由间切换不应该重复触发 useEffect(没依赖), 事实上console.log会重复执行; 具体原因就是第一条信息说明的

@apathyjade
Copy link
Author

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)[ ice/ packages/ runtime/ src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

你的问题可以通过调整 绑定事件的节点 或者 触发的时间节点绕过过去

我是在layout的useEffect里面给window注册了message事件 我需要在详情页回到列表页的时候通知刷新或者不刷新 但是在我进入详情页的时候 这个事件被注销了 所以我详情页回到列表页的时候 监听不到消息 我目前的解决方案是在发送消息的时候 套一个setTimeout 让它变成宏任务 这样它可以在layout注册事件后触发 这样是可以监听到的

可以使用 useLayoutEffect 绑定事件

是的 换成 useLayoutEffect 绑定事件是可以的 感谢

@apathyjade useLayoutEffect 有几率不生效(发送消息后才执行注册事件)

不应该啊,正常来说 useLayoutEffect 是先于 useEffect 执行, 除非是不再一个周期,或有绑定事件有异步干扰;

@ClarkXia
Copy link
Collaborator

@apathyjade 可以直接提供下 layout 的相关代码

import {  useEffect } from 'react';

import { Outlet } from 'ice';

const PageLayout = () => {
  useEffect(() => {
    console.log('切换子路由');
  }, [])
  return <Outlet />
}; 

export default PageLayout;

最基础的一个layou.tsx; 正常来说 在当前模版下的子路由间切换不应该重复触发 useEffect(没依赖), 事实上console.log会重复执行; 具体原因就是第一条信息说明的

并没有复现出类似问题,如果有需要可以重开 issue,并提供完整的复现 demo

@lhb2631225005
Copy link

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)[ ice/ packages/ runtime/ src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)[ ice/ packages/ runtime/ src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)[ ice/ packages/ runtime/ src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx](https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建;
[ice/packages/runtime/src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)[ ice/ packages/ runtime/ src /ClientRouter.tsx]([https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)%5B) ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsx)
if (process.env.ICE_CORE_ROUTER === 'true') { // Clear router before re-create in case of hot module replacement. clearRouter(); // @ts-expect-error routes type should be AgnosticBaseRouteObject[] router = createRouter(routerContext).initialize(); disableHistoryWarning(); // Replace history methods by router navigate for backwards compatibility. setHistory(createRouterHistory({ ...routerContext.history }, router)); } 每次切换路由时 触发更新ClientRouter 导致router重新创建;
https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx // 614row 614行 React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);React.useLayoutEffect(() => router.subscribe(setState), [路由器, setState]); // 739 row {state.initialized || router.future.v7_partialHydration ? ( ) : ( fallbackElement )} state.initialized 在这个过程中会从false变为true 导致MemoizedDataRoutes会被卸载重新创建

我也遇到了同样的问题 在layout里注册的事件 在进入二级路由的页面的时候 触发了layout的useEffect销毁周期 导致事件被销毁 二级路由触发了订阅事件也无效 因为layout里注册的事件已经被卸载掉了

你的问题可以通过调整 绑定事件的节点 或者 触发的时间节点绕过过去

我是在layout的useEffect里面给window注册了message事件 我需要在详情页回到列表页的时候通知刷新或者不刷新 但是在我进入详情页的时候 这个事件被注销了 所以我详情页回到列表页的时候 监听不到消息 我目前的解决方案是在发送消息的时候 套一个setTimeout 让它变成宏任务 这样它可以在layout注册事件后触发 这样是可以监听到的

可以使用 useLayoutEffect 绑定事件

是的 换成 useLayoutEffect 绑定事件是可以的 感谢

@apathyjade useLayoutEffect 有几率不生效(发送消息后才执行注册事件)

不应该啊,正常来说 useLayoutEffect 是先于 useEffect 执行, 除非是不再一个周期,或有绑定事件有异步干扰;

当时我第一时间尝试 发现可以 就反馈了 结果我在开发其他功能的时候发现了这个有时候会不成功的情况
我这个好像并不涉及到异步 业务逻辑是列表页统一做了缓存处理 在新建/编辑页面提交后判断 如果当前是新建 就刷新列表页的缓存 具体实现是判断如果是新建 就发送消息 然后在layout的useEffect监听事件 监听到就刷新列表页的缓存

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants