Как проверить хуки с помощью двух операторов useEffect?

У меня есть следующий крючок:


const useBar = () => {
  const [myFoo, setFoo] = useState(0);
  const [myBar, setBar] = useState(0);
  useEffect(() => {
    setFoo(myFoo + 1);
    console.log("setting foo (1)", myFoo, myBar);
  }, [setFoo, myFoo, myBar]);
  useEffect(() => {
    setBar(myBar + 1);
    console.log("setting bar (2)", myFoo, myBar);
  }, [setBar, myBar, myFoo]);
};

При работе с компонентом у меня ожидаемое поведение бесконечного цикла:

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

const Bar = () => {
  useBar();
  return <div>Bar</div>;
};

function App() {
  return (
    <Bar />
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Из console.log:

setting foo (1) 1 1
setting bar (2) 1 1
setting foo (1) 2 2
setting bar (2) 2 2
setting foo (1) 3 3
setting bar (2) 3 3
...

Однако тестирование это с @testing-library/react-hooks дает только первый вывод цикла:

describe("Tests", () => {
  test("useBar", async () => {
    const { rerender } = renderHook(() => {
      return useBar();
    });

    // await waitForNextUpdate();
    // tried the above doesn't work

    // rerender(); 
    // with rerender it loops through the next "cycle"
  });

});

Было интересно, как правильно проверить хуки, не звоня rerender и имитировать то же поведение, что и React - повторно визуализировать компонент при изменении состояния.

1 ответ

Решение

Я думаю, вы хотите проверить hook который использует useEffect и сообщить об ошибке, когда происходит бесконечный цикл. Но на самом деле мы не можем протестировать бесконечный цикл, мы можем установить ограничение только на количество раз. Когда цикл превышает этот предел, мы думаем, что он будет продолжать цикл бесконечно. Что касается того, является ли это на самом деле бесконечным циклом, это нелегко доказать.

Тем не менее, это не так просто проверить повторение useEffect, Хотя с помощью waitForNextUpdate может вызвать ошибку тайм-аута, эта ошибка также может быть вызвана длительной асинхронной операцией, и в качестве модульного теста вам понадобится быстрая обратная связь. Вы не можете ждать тайм-аут каждый раз. Это пустая трата времени.

Спасибо за эти проблемы, я нашел направление. Предоставить способ запуска useEffect из тестов

Когда я заменяю useEffect с участием useLayoutEffectЯ могу получить Maximum update depth exceeded ошибка быстро и точно. Это нужно только заменить useEffect с участием useLayoutEffect в обязательном тесте. Тест не пройден, когда цикл бесконечен.

Редактировать тест useEffect бесконечный цикл

import React from 'react'
import { renderHook } from '@testing-library/react-hooks'

import useBar from './useBar'

describe('Replace `useEffect` with `useLayoutEffect` to check for an infinite loop', () => {
  let useEffect = React.useEffect
  beforeAll(() => {
    React.useEffect = React.useLayoutEffect
  })
  afterAll(() => {
    React.useEffect = useEffect
  })
  it('useBar', async () => {
    const { result } = renderHook(() => useBar())
  })
})
Другие вопросы по тегам