Closed avainola closed 9 months ago
Hey, thanks for detailed report. I think the mentioned part can be omited (if (!isLoaded) {
).
It's already quite some time I've written this code and I think that was supposed to be some optimization, but I guess it did more harm than good.
Reporting with the assumption (based on https://tolgee.io/js-sdk/integrations/react/api#function-t) that
t
function fromuseTranslate
hook should trigger component update/re-render when translations change.After a bit of debugging (but without having deep understanding of the inner workings of
@tolgee/core
), I think there is a race condition happening that sometimes results in newt
function not being created after translations change. Since it is a race condition, it is not easy to create a minimal reproducible example, but if you are not able to reproduce it, I will try to find time to do it. I'll try to share/explain my finding and if my assumptions are wrong or I have misunderstood how it should be working, then sorry for the confusion.The problem seems to be in the
useTranslateInternal
hook, more specifically these LOCs. Problem:https://github.com/tolgee/tolgee-js/blob/main/packages/react/src/useTranslateInternal.ts#L40
isLoaded
is hook scope variable, beings re-evaluated every time the component using theuseTranslate
hook is re-rendering. This mean it does not always reflect to actualtolgee
instance state. I think it would be more correct to push this value from the event stream when it changes instead of relying on component re-render to have correct/up-to-date value.https://github.com/tolgee/tolgee-js/blob/main/packages/react/src/useTranslateInternal.ts#L42-L55
This effect creates new subscription and unsubscribes from the (previous) subscription that will be replaced by the new. The culprit (and the question I haven't figured out - "why is it needed?") here is that it depends on
isLoaded
(which depends on component re-renders), meaning unsubscribing and creating a new subscription is not determined only by input arguments andtolgee
state, but also on how often the component is re-rendering.https://github.com/tolgee/tolgee-js/blob/main/packages/core/src/Controller/Events/EventEmitterSelective.ts#L77-L86
https://github.com/tolgee/tolgee-js/blob/main/packages/core/src/Controller/Events/Events.ts#L58-L60
Translation changes are emitted asynchronously (with
delayed: true
).Now, If we put all this together:
tolgee
cache has updated, but the subscribers are yet not notified about the update.isLoaded
changes fromfalse
totrue
, it will unsubscribe, but not re-subscribe, since theuseEffect
hook is subscribing conditionally. This would not be a problem if event emitter would consider the subscribers at the moment of the event happening, but since it is not, it does not call the subscribers that unsubscribe after the event happening, but before the callbacks/handlers are being called.t
function causing a re-render (callingt
function insideReact.useMemo
that depends ont
).Unfortunately, I don't know the library well enough to suggest a change/PR at this point.