Replies: 3 comments
-
关于这个案例中 React 反直觉的调用顺序问题可以查看这个 codesandbox https://codesandbox.io/s/why-test2-not-updated-82890q?file=/src/index.js |
Beta Was this translation helpful? Give feedback.
0 replies
-
目前来看,explorer 消失的时候是因为 tabbar 没有选中 currentContainerId |
Beta Was this translation helpful? Give feedback.
0 replies
-
之前看到一段代码,可能跟这种现象有一点关联 layout.service.ts#L416 感觉跟 |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
我们在更新到 2.16 之后,偶现编辑器消失,当时(#734 )判断到是使用 resizeHandle 的时候没有判空,当时是有想到生命周期的事情的(在 NextBottomTabRenderer 这个 React 组件被渲染时,通过 useLayoutEffect 生命周期将 resizeHandle 放入 TabBar,如果在这个 resizeHandle 被注册之前调用 bottomExpanded,就会因为没有判断 undefine 而报错 ),但当时没有细想,只把这个 case 解决了,现在又遇到了一次文件树消失的问题,已经确定了是由于生命周期导致的一些问题,这里想拉出来看一下。
我们的文件树没有渲染的原因
我们的代码在 ToolBarActionContribution.registerToolbarActions 中注册的一个按钮,我们使用了 button 组件,传入了一个 delegate 方法,按钮在渲染的 useEffect(, []) 周期时会调用
props.delegate(
,我们在 delegate 中使用了 layoutService.getTabbarHandler('explorer').activate() 取 explorer,然后没有判空,此时就会报错: TypeError: Cannot read property 'activate' of undefined。所以这个组件就会因为 useEffect 内抛错渲染失败。这里是我们的代码问题,1 是没有判断 getTabbarHandler 的结果为空,2 是应该
await layoutService.viewReady.promise
。视图渲染问题
那么为什么 button 渲染时挂了会导致最后的文件树出现问题呢?
ToolbarLocation 这个类是负责 toolbar 的渲染的,我们之前注册的 registerToolbarActions 就会在这里被渲染,在一系列复杂的调用中,最后我们通过 renderToolbarLocation > ReactDOM.render 来渲染 toolbar,然后我们会在一些 Event.on 的回调中多次调用这个 renderToolbarLocation 函数。
然后因为我们的设计问题,这个 ReactDOM.render 的报错不仅会影响当前组件。关于这一块可以请 @MMhunter 来写一篇 React 的踩坑文章。
那么来回看 OpenSumi 整个视图的渲染,从我们调用 ClientApp.start 之后,ClientApp 会先后执行 renderApp, initializeContributions, onStartContributions 这三个方法。
整个渲染是从 ClientApp.renderApp 这个方法开始的,renderApp 中会有我们传入的的 Layout,然后我们会调用 React.render 把这个 Layout 渲染出来。
其中,Layout 里有一个很重要的部分是 SlotRenderer,就是一个个的插槽,我们可以声明在哪个插槽上插入哪些 modules: defaultConfig,在 SlotRenderer 渲染时会把这里声明的 modules 取出来,然后一个个渲染他们。
我们可以定义某个 slot 使用什么样的 Render 来渲染,比如我们就把 left, right, bottom 都使用 TabbarRenderer 来渲染,那么这些配置我们是怎么实现的呢?都是靠 MainLayoutModuleContribution 这个 Contribution,它会在以下几个 ClientApp 的生命周期中做一些事情:
registerComponent 真实要渲染的 Component,它和上面提到的 defaultConfig 里的值是要一一对应的,就会在这些 slot 渲染这些 modules 对应的 component
registerSlotRenderer 就是上面说的 SlotRenderer 了。
IMainLayoutService.didMount()
SlotRenderer 中会有一个 appInitialized.promise.then 的回调,你在 ClientApp.initialize 时注册的 component 是会被重新渲染的。
然后在
IMainLayoutService.didMount
中,开始调用所有 MainLayoutContribution 的 onDidRender 方法。我们可以在这些钩子上做一些对自己当前模块的处理之类的。注意一定要使用await layoutService.viewReady
Beta Was this translation helpful? Give feedback.
All reactions