【问题标题】:React Maximum update depth exceeded error caused by useEffect only in test仅在测试中由 useEffect 引起的 React Maximum update depth exceeded 错误
【发布时间】:2021-04-19 10:40:24
【问题描述】:

我正在尝试使用 jest 和 react-testing-library 为我的 react 组件编写一些测试。

我的组件看起来像:

//DocumentTable.js
import {useTranslation} from "react-i18next";
import ReactTable from "react-table-6";
import {connect} from "react-redux";
...

export const DocumentTable = ({documents, getDocuments, ...}) => {
    const {t} = useTranslation();
    const [data, setData] = useState([])

    useEffect(() => {
        getDocuments();
    }, [])

    useEffect(() => {
        setData(() => translate(documents.map(doc => Object.assign({}, doc))))
    }, [documents, t])

    const translate = (tempDocuments) => {
        if (tempDocuments[0]) {
            if (tempDocuments[0].name) {
                tempDocuments.forEach(doc => doc.name = t(doc.name));
            }
            if (tempDocuments[0].documentStatus) {
                tempDocuments.forEach(doc => doc.documentStatus = t(doc.documentStatus));
            }
        }
        return tempDocuments;
    }
    ...

        return (
            <div className="col m-0 p-0 hidden-overflow-y">

                <ReactTable
                    className="bg-dark dark-table"

                    data={data}
            ...
            )
}

...

export default connect(mapStateToProps, matchDispatchToProps)(DocumentTable);

如您所见,我正在使用来自 react-i18next 的 redux 和翻译。 我正在使用这个组件来显示从 react-table-v6 的 ReactTable 组件中的 prop 文档接收到的值。为了避免编辑我的原始值,我创建了文档数组的深层副本,将其翻译并放入直接在我的表中使用的数据中。

我已经开始编写我的测试,检查我是否可以使用 react-testing-library 正确渲染我的组件:

//DocumentTable.test.js
import React from 'react'
import {render} from '@testing-library/react'
import {DocumentTable} from "../../../components/content/DocumentTable";
import {I18nextProvider} from "react-i18next";
import i18n from "../../../i18n";

it("Should render component", () => {
    const documents = [
        {
            name: "favourite",
            documentStatus: "new"

        },
        {
            name: "simple",
            documentStatus: "edited"
        }
    ]

    render(
        <I18nextProvider i18n={i18n}>
            <DocumentTable documents={documents} getDocuments={jest.fn()}/>
        </I18nextProvider>
    );
})

一切似乎都运行良好。但是,我想像在其他组件测试中那样使用 useTranslation 钩子的模拟。 我的模拟是:

//_mocks_/react-18next.js
module.exports = {
    useTranslation: () => ({
        t: key => key,
        i18n: {}
    }),
}

为了使用它,我在 jest config 中添加了属性:

//package.json
  "jest": {
    "moduleNameMapper": {
      "react-i18next": "<rootDir>/src/tests/_mocks_/react-i18next.js"
    }
  },

我已经简化了我的测试:

//DocumentTable.test.js
import React from 'react'
import {render} from '@testing-library/react'
import {DocumentTable} from "../../../components/content/DocumentTable";

it("Should render component", () => {
    const documents = [
        {
            name: "favourite",
            documentStatus: "new"

        },
        {
            name: "simple",
            documentStatus: "edited"
        }
    ]

    render(
          <DocumentTable documents={documents} getDocuments={jest.fn()}/>
    );
})

现在当我运行测试时出现以下错误:

Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
        in DocumentTable (at DocumentTable.test.js:89)

我不明白发生了什么。我得出的结论是,问题是由 DocumentTable.js 文件中的 useEffect 挂钩引起的。当我不创建道具副本而是直接翻译时:

useEffect(() => {
    setData(() => translate(documents))
}, [documents, t])

一切又正常了。但是我必须继续创建它的副本(当用户更改语言时,我想再次翻译原始文件)。 我该如何处理? 提前致谢。

【问题讨论】:

    标签: reactjs use-effect react-testing-library react-i18next


    【解决方案1】:

    问题是你的模拟每次都会返回一个新函数t,这将触发你组件中的useEffect,因为t是一个依赖项。

    使用

    //_mocks_/react-18next.js
    const t = key => key;
    module.exports = {
        useTranslation: () => ({
            t,
            i18n: {}
        }),
    }
    

    【讨论】:

    • 拯救我的一天,非常感谢。但是你能解释一下为什么当我没有在 useEffect 钩子中复制文档的值并翻译原始数据时它会起作用吗?
    • 不太确定,但如果你不翻译数据,那么你的组件就不需要重新渲染/执行,因此useTranslation 不会被再次调用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-11
    • 1970-01-01
    • 2013-10-11
    • 2021-05-25
    • 2020-12-06
    • 2021-05-05
    • 1970-01-01
    相关资源
    最近更新 更多