CodePudding user response:
You are actually closer than you realize. Instead of returning a callback cb
to the UI to call as an unintentional side-effect, create/move some state into the hook.
The TranslationProvider
stores the current global language
state, but the useTranslation
hook should/could store it's own reference to a LocalizedStrings
object and store the translated messages in a local state that is updated via a useEffect
hook.
Example:
const useTranslation = (_strings, key) => {
// Access global language state and setter
const { language, setLanguage } = useContext(TranslationContext);
// Local message state for translations
const [message, setMessage] = useState();
// LocalizedStrings instance ref
const stringsRef = useRef(_strings && new LocalizedStrings(_strings));
// Side-effect to translate to current language
// Update message state to trigger rerender
useEffect(() => {
stringsRef.current?.setLanguage(language);
setMessage(stringsRef.current?.message);
}, [language]);
// Expose context value and current translated message
return { language, message, setLanguage };
};
Usage:
const strings = {
en: { message: "Test message in English" },
fr: { message: "Message de test en Français" }
};
const Test = () => {
const { message } = useTranslation(strings, "Test");
useEffect(() => {
console.log("[RENDER <Test/>", strings);
});
return <div>{message}</div>;
};
...
const _strings = {
en: { message: "Test message #2 in English" },
fr: { message: "Message de test #2 en Français" }
};
const Test2 = () => {
const { language, message } = useTranslation(_strings, "Test2");
useEffect(() => {
console.log("[RENDER] <Test2/>", _strings);
})
return (
<div>
{message} {language}
</div>
);
};