React i18next languageChanged 事件被多次调用

Sag*_*Gor 3 i18next reactjs react-i18next

我在我的 React js 应用程序中使用 i18next 进行翻译。我在 Header.jsx 文件中添加了所有页面通用的语言下拉列表。我正在我的页面quiz.jsx之一中根据当前语言获取数据。因此,在语言更改时应该再次调用 api。

问题解释

  1. i18Next 函数的languageChanged()事件在语言下拉列表更改时多次调用。它应该只被调用一次。我不知道为什么这个函数被多次调用?

  2. 我想仅在一个页面上实现i18Next 的languageChanged()事件,但目前它在每个页面上调用。所以 api 正在获取所有页面中的数据,这些数据对于该页面来说是不必要的数据。

i18Next 配置

语言.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;
Run Code Online (Sandbox Code Playgroud)

标头.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);
Run Code Online (Sandbox Code Playgroud)

测验.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);
Run Code Online (Sandbox Code Playgroud)

adr*_*rai 5

我怀疑问题是:

i18n.on('languageChanged', () => {
    getAllData();
});
Run Code Online (Sandbox Code Playgroud)

每次组件呈现时,它都会再次订阅 languageChanged 事件...

尝试将其移动到 useEffect 中,如下所示:

const handleLanguageChanged = useCallback(() => {
    getAllData();
}, []);

useEffect(() => {
    i18n.on('languageChanged', handleLanguageChanged);
    return () => {
        i18n.off('languageChanged', handleLanguageChanged);
    };
}, [handleLanguageChanged]);
Run Code Online (Sandbox Code Playgroud)