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>
我有一个多次使用的可重用组件来显示不同的下拉按钮。 它使用 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>