React (typescript)钩子的执行顺序



我正在努力使用语言切换功能。我的应用程序的主页应该拾取以前的本地存储设置,'preferredLanguage',或者从navigator.language中拾取默认语言(如果没有设置首选项)。它应该能够处理设置首选项和页面语言的lang路由/cat/es,并重定向到/。

它看起来像这样:

一个useLang钩子,用于设置首选和切换lang


export const useLang = (lang: string) => {
const { t, i18n } = useTranslation()
useEffect(() => {
console.log(`Setting lang to ${lang}`);
localStorage.setItem('preferredLanguage', lang);
i18n.changeLanguage(lang);
document.title = t('PageTitle');
}, [])
}

App.tsx

const SetLang = ({ lang }: {lang: string}) => {
useLang(lang);
return (
<Redirect to='/'/>
)
}
export const App = () => {
const { t } = useTranslation();
const targetLang = localStorage.getItem('preferredLanguage') ?? navigator.language.includes("es") ? "es" : "cat";
// Debug: 
useEffect(() => {
console.log(`Preferred: ${localStorage.getItem('preferredLanguage')}, Default: ${navigator.language.includes("es") ? "es" : "cat"}, Will set lang to ${targetLang}`);
}, []);
useLang(targetLang); // Y U NO WORK?
return (
<Router>
<Switch>
<Route exact path="/es" >
<SetLang lang="es" />
</Route>
<Route exact path="/cat" >
<SetLang lang="cat" />
</Route>
<Route exact path="/">
<HomePage/>
</Route>
// ...etc
</Switch>
<Router>
)

执行给出以下日志记录:

Preferred: es, Default: es, Will set lang to es App.tsx:25
Setting lang to es

然后我转到/cat并期望它切换到加泰罗尼亚语,但随后的调用发生将其切换回es:

Setting lang to cat 
Preferred: cat, Default: es, Will set lang to es
Setting lang to es

我困惑。有些东西不像我预料的那样。我看到表达式localStorage.getItem('preferredLanguage') ?? navigator.language.includes("es") ? "es" : "cat";应该解析为'cat',如果它存在于localStorage日志记录建议。在页面重新加载后,我检查localStorage并产生'es',正如上次调用useLang时所期望的那样。

我错过了什么?

感谢

useLang的deps也应该包括lang。我很确定你会得到一个警告。试着把它改成这样:

export const useLang = (lang: string) => {
const { t, i18n } = useTranslation()
useEffect(() => {
console.log(`Setting lang to ${lang}`);
localStorage.setItem('preferredLanguage', lang);
i18n.changeLanguage(lang);
document.title = t('PageTitle');
}, [lang])
}

我没有正确使用钩子。现在我在其中定义了一个函数并返回它,将有效的代码限制在该函数中。

import {useTranslation} from 'react-i18next';
export const useLang = () => {
const { t, i18n } = useTranslation()
const setLang = (lang?: string) => {
const preferredLang = localStorage.getItem('preferredLanguage')
const defaultLang = navigator.language.includes("es") ? "es" : "cat";
const targetLang = preferredLang ?? defaultLang;
console.log(`Preferred: ${localStorage.getItem('preferredLanguage')}, Default: ${navigator.language.includes("es") ? "es" : "cat"}, Will set lang to ${targetLang}`);
if(lang){
localStorage.setItem('preferredLanguage', lang);
i18n.changeLanguage(lang);
}else{
localStorage.setItem('preferredLanguage', targetLang);
i18n.changeLanguage(targetLang);
}
document.title = t('PageTitle');
}
return {setLang}
}
export const App = () => {
const {setLang} = useLang();

useEffect(() => {
setLang(); // TY!
}, []);
return (...)
}

请注意,尽管preferredLang和defaultLang正在更新(以前它们只是表达式),但targetLang没有更新,因为它在钩子上被关闭了。因此产生了导致Preferred: cat, Default: es, Will set lang to es行的奇怪情况(奇怪是因为它表明'cat' ?? 'es'被解析为'es')

感谢

最新更新