alibaba / ice

🚀 ice.js: The Progressive App Framework Based On React(基于 React 的渐进式应用框架)
https://ice.work
MIT License
17.83k stars 2.09k forks source link

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

Open apathyjade opened 2 weeks ago

apathyjade commented 2 weeks ago

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

[ice](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/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 ? ( <MemoizedDataRoutes routes={router.routes} future={router.future} state={state} /> ) : ( fallbackElement )}

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

lhb2631225005 commented 1 week ago

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

[ice](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/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 commented 1 week ago

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建; [ice](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/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](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/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 commented 1 week ago

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建; [ice](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/master/packages/runtime/src) /ClientRouter.tsx[ ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsxif (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](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/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 commented 1 week ago

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建; [ice](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/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](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/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 commented 1 week ago

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

lhb2631225005 commented 1 week ago

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建; [ice](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/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](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/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 commented 1 week ago

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建; [ice](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/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.tsxif (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](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/master/packages/runtime/src) /ClientRouter.tsx[ ice/ packages/ runtime/ src /ClientRouter.tsx]( https://github.com/alibaba/ice/blob/master/packages/runtime/src/ClientRouter.tsxif (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 commented 1 week ago

@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 commented 1 week ago

说明 /page/layout.tsx /page/a.tsx /page/b.tsx 在a、b子路由页面间切换时 layout布局组件会被销毁再重新创建; [ice](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/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](https://github.com/alibaba/ice/tree/master)/[packages](https://github.com/alibaba/ice/tree/master/packages)/[runtime](https://github.com/alibaba/ice/tree/master/packages/runtime)/[src](https://github.com/alibaba/ice/tree/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 执行, 除非是不再一个周期,或有绑定事件有异步干扰;