多次调用 React i18next languageChanged 事件
React i18next languageChanged event called multiple times
我在我的 React JS 应用程序中使用 i18next 进行翻译。我在 Header.jsx 文件中添加了一个语言下拉列表,这对所有页面都是通用的。我正在根据我的其中一个页面 quiz.jsx 中的当前语言获取数据。所以在语言更改时 api 应该再次调用。
问题说明
languageChanged() i18Next 函数的事件在语言下拉列表更改时多次调用。它应该只被调用一次。我不知道为什么这个函数被多次调用?
我只想在一页上实现 i18Next 的 languageChanged() 事件,但目前它正在每一页上调用。所以 api 正在获取所有页面中的数据,这对于该页面来说是不必要的数据。
i18下一个配置
language.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import config from './config';
var resources = {};
//Dynamically reading languages from config file
config.supportedLanguages.forEach(element => {
resources[element] = {
translations: require('../locale/' + element + '.json')
};
});
i18n.use(initReactI18next).init({
fallbackLng: config.defaultLanguage,
lng: config.defaultLanguage,
resources,
ns: ['translations'],
defaultNS: 'translations',
debug:true
});
i18n.languages = config.supportedLanguages;
export default i18n;
Header.jsx
import React, { useState, useEffect } from 'react';
import { Dropdown, DropdownButton } from 'react-bootstrap';
import { withTranslation, useTranslation } from 'react-i18next';
import * as api from "../../utils/api";
const TopHeader = ({ t }) => {
const { i18n } = useTranslation();
// language selector
const [languageValue, setLanguageValue] = useState('')
const [languages, setLanguages] = useState('');
const languageChange = (data) => {
setLanguageValue(data.language)
i18n.changeLanguage(data.code);
localStorage.setItem('language', JSON.stringify(data));
}
const getUserSelectedLanguage = () => {
var user_selected_lang = localStorage.getItem('language');
if (user_selected_lang && user_selected_lang !== undefined) {
user_selected_lang = JSON.parse(user_selected_lang);
}
return user_selected_lang;
}
//api render
useEffect(() => {
api.getLanguages().then((response) => {
if (!response.error) {
setLanguages(response.data);
var user_selected_lang = getUserSelectedLanguage();
if (user_selected_lang) {
selectUserLanguage(user_selected_lang);
} else {
var index = response.data.filter((data) => {
return data.code === config.defaultLanguage;
})
selectUserLanguage(index[0]);
}
}
});
}, []);
return (
<React.Fragment>
<div className="small__top__header">
<div className="row justify-content-between align-items-center">
<div className="col-md-6 col-12">
<div className="dropdown__language">
<DropdownButton className="inner-language__dropdown" title={languageValue ? languageValue : "Select Language"}>
{languages && languages.map((data, key) => {
return (
<Dropdown.Item onClick={() => languageChange(data)} value={languageValue} id={data.id} active={languageValue === data.language ? "active" : ""} key={data.language}>{data.language}</Dropdown.Item>
)
})}
</DropdownButton>
</div>
</div>
</div>
</div>
</React.Fragment>
)
}
export default withTranslation()(TopHeader);
quiz.jsx
import React, { useState, useEffect } from 'react';
import { withTranslation, useTranslation } from 'react-i18next';
import { Spinner } from 'react-bootstrap';
const Quiz = ({ t }) => {
const [category, setCategory] = useState({ all: '', selected: '' });
const [subCategory, setsubCategory] = useState({ all: '', selected: '' });
const [level, setLevel] = useState([]);
const { i18n } = useTranslation();
useEffect(() => {
getAllData();
}, []);
i18n.on('languageChanged', () => {
getAllData();
});
const getAllData = () => {
// This function will call the Category , Subcategory and Level API to fetch the data
// And set the local states
}
return (
<React.Fragment>
<Header />
<div className="quizplay mb-5">
<div className="container">
<div className="row morphisam mb-5">
<div className="col-xxl-3 col-xl-4 col-lg-4 col-md-12 col-12">
<div className="left-sec">
{/* left category sec*/}
<div className="bottom__left">
<div className="cat__Box">
<span className="left-line"></span>
<h3 className="quizplay__title text-uppercase text-white font-weight-bold">{t('Categories')}</h3>
<span className="right-line"></span>
</div>
<div className="bottom__cat__box">
<ul className="inner__Cat__box">
{
category.all ? category.all.map((data, key) => {
return (
<li className='d-flex' key={key} onClick={() => handleChangeCategory(data)}>
<div className={`w-100 button ${category.selected && category.selected.id === data.id ? "active-one" : "unactive-one"}`}>
<span className="Box__icon">
<img src={data.image} alt="" />
</span>
<p className="Box__text">{data.category_name}</p>
</div>
</li>
)
})
:
<div className='text-center'>
<Spinner animation="border" role="status"></Spinner>
</div>
}
</ul>
</div>
</div>
</div>
</div>
{/* sub category middle sec */}
<div className="col-xxl-9 col-xl-8 col-lg-8 col-md-12 col-12">
<div className="right-sec">
<SubCatslider data={subCategory.all} selected={subCategory.selected} onClick={handleChangeSubCategory} />
</div>
<div className="right__bottom cat__Box mt-4">
<span className="left-line"></span>
<h6 className="quizplay__title text-uppercase text-white font-weight-bold">{t('levels')}</h6>
<span className="right-line"></span>
</div>
{/* levels sec */}
<div className="row level-row">
<UnlockLevel count={level.count} category={category.selected} subcategory={subCategory.selected} unlockedLevel={level.unlockedLevel} />
</div>
</div>
</div>
</div>
</div>
</React.Fragment>
)
}
export default withTranslation()(Quiz);
我怀疑问题是:
i18n.on('languageChanged', () => {
getAllData();
});
每次组件呈现时,它都会再次订阅 languageChanged 事件...
尝试在useEffect中移动它,比如:
const handleLanguageChanged = useCallback(() => {
getAllData();
}, []);
useEffect(() => {
i18n.on('languageChanged', handleLanguageChanged);
return () => {
i18n.off('languageChanged', handleLanguageChanged);
};
}, [handleLanguageChanged]);
我在我的 React JS 应用程序中使用 i18next 进行翻译。我在 Header.jsx 文件中添加了一个语言下拉列表,这对所有页面都是通用的。我正在根据我的其中一个页面 quiz.jsx 中的当前语言获取数据。所以在语言更改时 api 应该再次调用。
问题说明
languageChanged() i18Next 函数的事件在语言下拉列表更改时多次调用。它应该只被调用一次。我不知道为什么这个函数被多次调用?
我只想在一页上实现 i18Next 的 languageChanged() 事件,但目前它正在每一页上调用。所以 api 正在获取所有页面中的数据,这对于该页面来说是不必要的数据。
i18下一个配置
language.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import config from './config';
var resources = {};
//Dynamically reading languages from config file
config.supportedLanguages.forEach(element => {
resources[element] = {
translations: require('../locale/' + element + '.json')
};
});
i18n.use(initReactI18next).init({
fallbackLng: config.defaultLanguage,
lng: config.defaultLanguage,
resources,
ns: ['translations'],
defaultNS: 'translations',
debug:true
});
i18n.languages = config.supportedLanguages;
export default i18n;
Header.jsx
import React, { useState, useEffect } from 'react';
import { Dropdown, DropdownButton } from 'react-bootstrap';
import { withTranslation, useTranslation } from 'react-i18next';
import * as api from "../../utils/api";
const TopHeader = ({ t }) => {
const { i18n } = useTranslation();
// language selector
const [languageValue, setLanguageValue] = useState('')
const [languages, setLanguages] = useState('');
const languageChange = (data) => {
setLanguageValue(data.language)
i18n.changeLanguage(data.code);
localStorage.setItem('language', JSON.stringify(data));
}
const getUserSelectedLanguage = () => {
var user_selected_lang = localStorage.getItem('language');
if (user_selected_lang && user_selected_lang !== undefined) {
user_selected_lang = JSON.parse(user_selected_lang);
}
return user_selected_lang;
}
//api render
useEffect(() => {
api.getLanguages().then((response) => {
if (!response.error) {
setLanguages(response.data);
var user_selected_lang = getUserSelectedLanguage();
if (user_selected_lang) {
selectUserLanguage(user_selected_lang);
} else {
var index = response.data.filter((data) => {
return data.code === config.defaultLanguage;
})
selectUserLanguage(index[0]);
}
}
});
}, []);
return (
<React.Fragment>
<div className="small__top__header">
<div className="row justify-content-between align-items-center">
<div className="col-md-6 col-12">
<div className="dropdown__language">
<DropdownButton className="inner-language__dropdown" title={languageValue ? languageValue : "Select Language"}>
{languages && languages.map((data, key) => {
return (
<Dropdown.Item onClick={() => languageChange(data)} value={languageValue} id={data.id} active={languageValue === data.language ? "active" : ""} key={data.language}>{data.language}</Dropdown.Item>
)
})}
</DropdownButton>
</div>
</div>
</div>
</div>
</React.Fragment>
)
}
export default withTranslation()(TopHeader);
quiz.jsx
import React, { useState, useEffect } from 'react';
import { withTranslation, useTranslation } from 'react-i18next';
import { Spinner } from 'react-bootstrap';
const Quiz = ({ t }) => {
const [category, setCategory] = useState({ all: '', selected: '' });
const [subCategory, setsubCategory] = useState({ all: '', selected: '' });
const [level, setLevel] = useState([]);
const { i18n } = useTranslation();
useEffect(() => {
getAllData();
}, []);
i18n.on('languageChanged', () => {
getAllData();
});
const getAllData = () => {
// This function will call the Category , Subcategory and Level API to fetch the data
// And set the local states
}
return (
<React.Fragment>
<Header />
<div className="quizplay mb-5">
<div className="container">
<div className="row morphisam mb-5">
<div className="col-xxl-3 col-xl-4 col-lg-4 col-md-12 col-12">
<div className="left-sec">
{/* left category sec*/}
<div className="bottom__left">
<div className="cat__Box">
<span className="left-line"></span>
<h3 className="quizplay__title text-uppercase text-white font-weight-bold">{t('Categories')}</h3>
<span className="right-line"></span>
</div>
<div className="bottom__cat__box">
<ul className="inner__Cat__box">
{
category.all ? category.all.map((data, key) => {
return (
<li className='d-flex' key={key} onClick={() => handleChangeCategory(data)}>
<div className={`w-100 button ${category.selected && category.selected.id === data.id ? "active-one" : "unactive-one"}`}>
<span className="Box__icon">
<img src={data.image} alt="" />
</span>
<p className="Box__text">{data.category_name}</p>
</div>
</li>
)
})
:
<div className='text-center'>
<Spinner animation="border" role="status"></Spinner>
</div>
}
</ul>
</div>
</div>
</div>
</div>
{/* sub category middle sec */}
<div className="col-xxl-9 col-xl-8 col-lg-8 col-md-12 col-12">
<div className="right-sec">
<SubCatslider data={subCategory.all} selected={subCategory.selected} onClick={handleChangeSubCategory} />
</div>
<div className="right__bottom cat__Box mt-4">
<span className="left-line"></span>
<h6 className="quizplay__title text-uppercase text-white font-weight-bold">{t('levels')}</h6>
<span className="right-line"></span>
</div>
{/* levels sec */}
<div className="row level-row">
<UnlockLevel count={level.count} category={category.selected} subcategory={subCategory.selected} unlockedLevel={level.unlockedLevel} />
</div>
</div>
</div>
</div>
</div>
</React.Fragment>
)
}
export default withTranslation()(Quiz);
我怀疑问题是:
i18n.on('languageChanged', () => {
getAllData();
});
每次组件呈现时,它都会再次订阅 languageChanged 事件...
尝试在useEffect中移动它,比如:
const handleLanguageChanged = useCallback(() => {
getAllData();
}, []);
useEffect(() => {
i18n.on('languageChanged', handleLanguageChanged);
return () => {
i18n.off('languageChanged', handleLanguageChanged);
};
}, [handleLanguageChanged]);