I tried searching for mentions of unstable reference to t returned by useTranslation and did not find anything. Also, the docs do not mention whether the reference is expected to be stable or not.
-->
useTranslation returns an unstable reference of t, this causes problems when using it on other hooks.
const { t } = useTranslation('fakespace');
// when not ready, `t` is always a different function every time `useTranslation` is invoked.
t should return a stable reference if arguments to useTranslation have not changed.
@eomuraliev If it should be memoized or not is a question the maintainers can answer, what I am wondering is, what are the problem when using it with other hooks? Are we talking about performance problems or? :thinking:
Thanks :two_hearts: :pray:
@tigerabrodi The problem is for example if I'm using t in a useEffect to show a user a localized notification, I need to make sure I have the latest and correct reference to t in the useEffect hook, so I want to include t in its dependencies. If t is not stable, then it will cause my useEffect to needlessly rerun all the time. It doesn't have to be a notification, it could be anything involving some string I need to localize in a hook that depends on t.
Roughly something like:
``js
const { t } = useTranslation('fakespace');
useEffect(() => {
// do something work
// show a notification with a string localized usingt`
},
[t])
I removed my guesses for where the problem is caused or how to solve it. I could be wrong on the causes, and I don't want it to distract from the discussion that t should be stable.
@eomuraliev Gotcha! Seems like memoziation would be the appropriate solution in my eyes as well, thanks for elaborating also! :tada:
Hey guys, t function it's a state, so it wouldn't need to be memoized: https://github.com/i18next/react-i18next/blob/master/src/useTranslation.js#L42. I think it may be something else. 馃
After some digging. I think the problem in my case is that the value returned for notReady is not stable. The useState portion is probably stable.
Do you mean ready property? If so, it's a boolean, it won't get a new "reference" on every rerender.
I mean the values returned when ready is false. https://github.com/i18next/react-i18next/blob/8fa7101bc0cb1c39a9ef9b9a47c9f497af08ee21/src/useTranslation.js#L11-L19
notReady gets created to be assigned to t every time the hook is called https://github.com/i18next/react-i18next/blob/8fa7101bc0cb1c39a9ef9b9a47c9f497af08ee21/src/useTranslation.js#L13
Seems like wrapping it in a useCallback could help? Then it would only be redeclared whenever k changes right?
k is an argument, so you could get away with just wrapping notReady in a useCallback with an empty dependencies array. Also, you would need to lift the declaration of notReady up out of the if, since hooks should not be conditionally invoked.
Isn't mandatory to pass i18n instance to react-i18next?
Yeah, this one is a bit tricky, one thing is for sure though, we wanna memoize it haha :smile:
@eomuraliev if you end in if (!i18n) it actually tells you - your config/setup is broken!!! you should never get into that execution path - it only exists to warn you that you got something wrong.
t function gets only set if something changes, same for the ready boolean (which as a boolean is a type and not a ref)
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I'm curious if there is any plan/progress on this issue, the only workaround I came up with was totally remove t from dependency array of hooks like useEffect (it triggers API calls in my case) , don't know if that has any negative consequences.
@akamfoad t is taken from state: https://github.com/i18next/react-i18next/blob/master/src/useTranslation.js#L42 -> it's replaced if either translations were loaded or language was changed -> which makes sense
so, not 100% sure what your issue is? But regarding API calls, I guess those do not depend on t so it should not be in dependency array
tis taken from state: https://github.com/i18next/react-i18next/blob/master/src/useTranslation.js#L42 -> it's replaced if either translations were loaded or language was changed -> which makes sense
I thought it could be stable between renders cuz it seems like same t function which is independent of translations and localization boilerplate, it takes a key (or keys and options) and returns a string (usually), don't know if that make sense.
so, not 100% sure what your issue is? But regarding API calls, I guess those do not depend on t so it should not be in dependency array
You're right, but I have a use case like below
useEffect(()=>{
const getSMTH = async () => {
try{
const res = await fetch("...");
setData(await res.json())
} catch(err){
setPopupText(t("Error_Key"))
}
}
getSMTH()
}, [aParam, anotherParam, t, setPopupText]);
Is there any pattern to the use cases you can think of then?
no - the t function is bound to the namespace set on useTranslation and acts as a rerender trigger prop for the case something changed and i18n needs rerendering. Every other case the t function is stable.
You got the t function mentioned in the issue -> than something is wrong in your code.
Regarding API call passing t -> you can use i18n.t for that case...or set an error state and call t on render
You got the t function mentioned in the issue -> than something is wrong in your code.
Nah sorry about that, I didn't mean to get help with my code hahaha.
What I meant was, I thought t is a function which takes an argument and depending on some global state (i18n object and its resources itc) returns a string, but seems it is more complicated than that.
I think the example was too small to make it obvs 馃槵
Thanks for the clarification @jamuhl
Most helpful comment
Yeah, this one is a bit tricky, one thing is for sure though, we wanna memoize it haha :smile: