react i18next 引入了使用 i18n 的 Hooks 顺序的变化

react i18next introduced a change in the order of Hooks using i18n

我有一个多次使用的可重用组件来显示不同的下拉按钮。 它使用 i18n。

这是我的代码:

import React from 'react';
import { Dropdown } from 'react-bootstrap';
import shortid from 'shortid';
import { useTranslation } from 'react-i18next';

const PropertyButton = (state, name, handle, list, i18nName) => {

    if (name === "Produttore") {
        console.log("aa")
     }

     const [ t, i18n ] = useTranslation();
    
        return (
               <Dropdown>
                    <Dropdown.Toggle className="choiceButton servingButton btn" key="{shortid.generate()}" 
                        item={name} onSelect={handle}>
                        {t(`wine.attribute.${name}`)}
                    </Dropdown.Toggle>

                    <Dropdown.Menu className="choiceButton servingButton btn">

                        { list === null || list === undefined ? <></> :
                        list.map(item => {
                            const val = item.name === undefined ? item : item.name;
                            return (
                                <Dropdown.Item key={shortid.generate()} kname={name} kvalue={val} onClick={handle}>
                                   { i18nName === "regionList" || i18nName === "produttore" || i18nName === "venditore" ? val : t(`wine.${i18nName}.${val}`)}
                                </Dropdown.Item>
                            )
                        }
                        )}
                    </Dropdown.Menu>
                </Dropdown>
        )
    };

export default PropertyButton;

该组件被多次调用,没有错误。 我不认为问题出在组件的主体上,因为它只显示了一个按钮。 i18n 或我使用它的方式应该有一些奇怪的地方。

有一种情况,当name === "Produttore"(我加了一个console.log只是为了打个断点),然后踩到const [ t, i18n ] = useTranslation();行会产生hook错误。

顺便说一句,我同时使用了 const [ t, i18n ] = useTranslation();const { t } = useTranslation(); 选项,结果相同。

Warning: React has detected a change in the order of Hooks called by NickSelection. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks

*************** 显示它的使用方式 **********************

根据要求,组件是这样的 used/called。 每次调用 PropertyButton returns 一个 Dropdown 按钮,使用传递的参数进行初始化。

它们都是 运行(不同语言),但只有带 Produttore 的那个(用 ===>>> 箭头表示)会产生错误。

const NickSelection = ({
    regionList,
    mainListContainsEffervescenza, mainListContainsTannicità,
    prezzo, setPrezzo,
    effervescenza, setEffervescenza,
    acidità, setAcidità,
    alcolicità, setAlcolicità,
    tannicità, setTannicità,
    tipologia, setTipologia,
    territorio, setTerritorio,
    produttore, setProduttore, producerList,
    venditore, setVenditore, sellerList
}) => {

    return (

            {/* <Footer */}
            <div className="footer_container footer_container_chat" style={{ zIndex: "6000" }}>
      {PropertyButton(tipologia, "Tipologia", handlePropertyButton, allowedProductTypes, "productType")}
      {PropertyButton(territorio, "Territorio", handlePropertyButton, regionList, "regionList")}
      {PropertyButton(acidità, "Acidità", handlePropertyButton, wineSensations, "sensation")}


      {mainListContainsEffervescenza ? PropertyButton(effervescenza, "Effervescenza", handlePropertyButton, wineSensationsWith0, "sensation") : <></>}
      {PropertyButton(alcolicità, "Alcolicità", handlePropertyButton, wineSensations, "sensation")}
      {mainListContainsTannicità ? PropertyButton(tannicità, "Tannicità", handlePropertyButton, wineSensationsWith0, "sensation") : <></>}
      {PropertyButton(prezzo, "Prezzo", handlePropertyButton, prices, "prices")}

      { producerList.length > 1 ? 
===>>>  PropertyButton(produttore, "Produttore", handlePropertyButton, producerList, "produttore") : <></> }

      { sellerList.length > 1 ? PropertyButton(venditore, "Venditore", handlePropertyButton, sellerList, "venditore") : <></>}

   </div>

};

export default NickSelection;

问题

您已经声明了一个常规 Javascript 函数,PropertyButton 并在您的代码中直接调用它。最终你是有条件地调用这个函数,因此调用的钩子顺序发生了变化。

<div className="...." style={{ ... }}>
  {PropertyButton(tipologia, "Tipologia", handlePropertyButton, allowedProductTypes, "productType")}
  {PropertyButton(territorio, "Territorio", handlePropertyButton, regionList, "regionList")}
  {PropertyButton(acidità, "Acidità", handlePropertyButton, wineSensations, "sensation")}

  {mainListContainsEffervescenza ? PropertyButton(effervescenza, "Effervescenza", handlePropertyButton, wineSensationsWith0, "sensation") : <></>}
  {PropertyButton(alcolicità, "Alcolicità", handlePropertyButton, wineSensations, "sensation")}
  {mainListContainsTannicità ? PropertyButton(tannicità, "Tannicità", handlePropertyButton, wineSensationsWith0, "sensation") : <></>}
  {PropertyButton(prezzo, "Prezzo", handlePropertyButton, prices, "prices")}

  {producerList.length > 1 ? PropertyButton(produttore, "Produttore", handlePropertyButton, producerList, "produttore") : <></> }

  {sellerList.length > 1 ? PropertyButton(venditore, "Venditore", handlePropertyButton, sellerList, "venditore") : <></>}

这违反了挂钩规则。

解决方案

尝试将 PropertyButton 转换为 React 组件,呈现 为 JSX.

import React from 'react';
import { Dropdown } from 'react-bootstrap';
import shortid from 'shortid';
import { useTranslation } from 'react-i18next';

const PropertyButton = ({ state, name, handle, list, i18nName }) => {
  ...
};

export default PropertyButton;

...

<div className="...." style={{ ... }}>
  <PropertyButton
    state={tipologia}
    name="Tipologia"
    handle={handlePropertyButton}
    list={allowedProductTypes}
    i18nName="productType"
  />
  ...etc...

  {mainListContainsEffervescenza && (
    <PropertyButton
      state={effervescenza}
      name="Effervescenza"
      handle={handlePropertyButton}
      list={wineSensationsWith0}
      i18nName="sensation"
    />
  )}
  ...etc...

  {producerList.length > 1 && (
    <PropertyButton
      state={produttore}
      name="Produttore"
      handle={handlePropertyButton}
      list={producerList}
      i18nName="produttore"
    />
  )}

  ...etc...

</div>