remesh-js/remesh

一个Query 使用useRemeshQuery和effect fromQuery同时订阅,effect的订阅会失效

Closed this issue · 8 comments

image
image

如果我把组件内的useRemeshQuery注释掉,effect的observable会执行。否则只会执行组件内的变更渲染。

急。。。

我看看

image

effect中fromQuery返回的subject.isStopped 是 true。不知道是我写的哪儿有问题导致的还是什么其他原因

我构造了一个测试用例,试图复现,但没有遇到你提的这个问题。

可以再排查一下,是不是意料之外地卸载了组件导致取消 effect 订阅了。

或者构造一个最小可复现 demo.

image

image

找到原因了,第一张图,我做了一个用户信息加载状态的判断,这个注释掉就没问题。
但是我在最外侧使用了RemeshScope,domain在组件销毁时不应该被销毁吧?

是的,RemeshScope 可以保活 domain 实例,理论上不会因为组件销毁所致的引用归零而自动回收掉。

不过,尽管 domain 不会被回收,但 domain-query 等领域资源还是会回收的。因此不再有引用的 domain-query 会被回收,因而 fromQuery(..)observablecompleted 掉。

对于 domain-query 层面的保活,目前可以通过下面的步骤来完成,后续可能考虑新增相关 API。

第一步,创建一个特殊的 domain-query

const HolderQuery = domain.query({
  name: 'HolderQuery',
  impl: ({ get }) => {
      get(AQuery())
      get(BQuery())
    // 其他需要保活的 query
    if (get(CQuery())) {
      // 还可以根据动态条件选择保活
       get(DQuery())
    }
  } 
})

这个特殊的 Query,返回 undefined,这样它不会引起组件的更新(每次都一样的值),但会记住它依赖的其它 domain-query

第二步,在合适的组件层级里,订阅 HolderQuery

const HolderComponent = ({ children  }: { children: ReactNode }) => {
  const domain = useRemeshDomain(MyDomain())
  useRemeshQuery(domain.query.HolderQuery())

   // 手动保活 domain
    useRemeshDomain(ChatDomain())
    useRemeshDomain(UserDomain())

    return <>{children}</>
}

// 这样用
<HolderComponent>
  <XXRouterProvider />
</HolderComponent>

通过上述方式,我们同时按需保活的 domain 和 domain-query,实现了 RemeshScope 的功能并做得更多。

对于 domain-query 层面的保活,目前可以通过下面的步骤来完成,后续可能考虑新增相关 API。

第一步,创建一个特殊的 domain-query

const HolderQuery = domain.query({
  name: 'HolderQuery',
  impl: ({ get }) => {
      get(AQuery())
      get(BQuery())
    // 其他需要保活的 query
    if (get(CQuery())) {
      // 还可以根据动态条件选择保活
       get(DQuery())
    }
  } 
})

这个特殊的 Query,返回 undefined,这样它不会引起组件的更新(每次都一样的值),但会记住它依赖的其它 domain-query

第二步,在合适的组件层级里,订阅 HolderQuery

const HolderComponent = ({ children  }: { children: ReactNode }) => {
  const domain = useRemeshDomain(MyDomain())
  useRemeshQuery(domain.query.HolderQuery())

   // 手动保活 domain
    useRemeshDomain(ChatDomain())
    useRemeshDomain(UserDomain())

    return <>{children}</>
}

// 这样用
<HolderComponent>
  <XXRouterProvider />
</HolderComponent>

通过上述方式,我们同时按需保活的 domain 和 domain-query,实现了 RemeshScope 的功能并做得更多。

好的,谢谢。建议在文档里提示一下这个问题,ScopeDomain介绍有些模糊了,会让人误解。

好的,这块确实得好好处理一下。