Проблема с использованием useDispatch Hook - Предупреждение: React обнаружил изменение в порядке хуков - PullRequest
1 голос
/ 28 января 2020

Это мой первый раз, когда я использую Redux Hooks в реакции.-нативно, но у меня возникают проблемы в моем тесте, потому что когда я запускаю тест, я получаю это предупреждение:

Предупреждение: React обнаружен изменение порядка хуков, вызываемых WarrantiesHomeButton. Это приведет к ошибкам и ошибкам, если не будет исправлено. Для получения дополнительной информации прочтите Правила зацепок:

   Previous render            Next render
   ------------------------------------------------------
1. useState                   useContext
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Я не уверен, что проблема в моем коде или в том, как я тестирую i, приложение работает нормально. Если я запускаю каждый тест независимо, тест проходит без предупреждения, если я запускаю все три теста, последний тест выдает предупреждение и ошибку.

Я был бы признателен, если бы вы, ребята, могли указать мне правильное направление, в котором я Я делаю ошибку.

ГарантииHomeButton. js

import React, { useState, useEffect, useCallback } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { WarrantiesHomeMenu } from '../WarrantiesHomeMenu';
import { userService } from '../services';
import { HomeButton } from '../components';
import { screenNames } from '../constants';
import { userActions } from '../store';
import PropTypes from 'prop-types';

const WarrantiesHomeButton = ({ navigation }) => {
  const [showWarrantiesMenu, setShowWarrantiesMenu] = useState(false);

  const { warrantiesLoginFlow, user } = useSelector(
    (state) => state.userReducer,
  );
  const dispatch = useDispatch();

  const handlePressWarranties = () => {
    if (!userService.isAuthenticated()) {
      dispatch(userActions.warrantiesLoginStart());
      navigation.navigate(screenNames.SIGN_UP);
    } else {
      setShowWarrantiesMenu(true);
    }
  };

  useEffect(() => {
    validateWarrantiesFlow();
  });

  const validateWarrantiesFlow = useCallback(() => {
    if (warrantiesLoginFlow && user.id) {
      setShowWarrantiesMenu(true);
      dispatch(userActions.warrantiesLoginStop());
    }
  }, [warrantiesLoginFlow, user.id, dispatch]);

  const handleModalPress = () => {
    setShowWarrantiesMenu(false);
    navigation.navigate(screenNames.SERVICE_CENTERS);
  };

  const closeWarrantiesHomeMenu = () => {
    setShowWarrantiesMenu(false);
  };

  return (
    <>
      <HomeButton
        testID="HomeButton"
        text="Revisiones garantía"
        icon="toolBox"
        onPress={handlePressWarranties}
      />

      <WarrantiesHomeMenu
        visible={showWarrantiesMenu}
        onPress={handleModalPress}
        navigation={navigation}
        closeModal={closeWarrantiesHomeMenu}
      />
    </>
  );
};

WarrantiesHomeButton.propTypes = {
  navigation: PropTypes.objectOf(PropTypes.any),
};

export { WarrantiesHomeButton };

ГарантииHomeButton.test. js

import * as React from 'react';
import { Provider } from 'react-redux';
import {
  render as rtlRender,
  fireEvent,
  wait,
  act,
} from '@testing-library/react-native';
import { userService } from '../services';
import { screenNames } from '../constants';
import { WarrantiesHomeButton } from './WarrantiesHomeButton';
import { store } from '@auteco/store';

jest.mock('@auteco/components', () => require('@auteco/test').mockComponents());

jest.mock('../WarrantiesHomeMenu', () => {
  const { mockComponent } = require('@auteco/test');
  return {
    WarrantiesHomeMenu: mockComponent('WarrantiesHomeMenu'),
  };
});

describe('<WarantiesHomeButton/>', () => {
  let mockProps;
  const setState = jest.fn();
  beforeAll(() => {
    mockProps = {
      navigation: {
        navigate: jest.fn(),
        dangerouslyGetParent: jest.fn(() => ({ state: null })),
      },
    };
    jest.spyOn(userService, 'isAuthenticated').mockReturnValue(true);
  });

  function render(ui) {
    return rtlRender(<Provider store={store}>{ui}</Provider>);
  }

  it('Should Render correctly', () => {
    const { baseElement } = render(<WarrantiesHomeButton {...mockProps} />);
    expect(baseElement).toMatchSnapshot();
  });

  describe('And user is authenticated', () => {
    describe('And button is pressed', () => {
      it('Should show WarrantiesMenu by setting setShowWarrantiesMenu state to true', async () => {
        jest.spyOn(React, 'useState').mockReturnValue([false, setState]);
        const { getByTestId } = render(<WarrantiesHomeButton {...mockProps} />);
        const button = getByTestId('HomeButton');
        button.props.onPress();
        await wait();
        expect(setState).toBeCalledWith(true);
      });
    });
  });

  describe('And user is not authenticated', () => {
    describe('And button is pressed', () => {
      it('Should navigate to signUpScreen', async () => {
        jest.spyOn(userService, 'isAuthenticated').mockReturnValue(false);
        jest.spyOn(React, 'useState').mockReturnValue([false, setState]);
        const { getByTestId } = render(<WarrantiesHomeButton {...mockProps} />);
        const button = getByTestId('HomeButton');
        act(() => {
          button.props.onPress();
        });
        expect(mockProps.navigation.navigate).toBeCalledWith(
          screenNames.SIGN_UP,
        );
      });
    });
  });
});

ошибка в консоли

  console.error node_modules/react-native/Libraries/YellowBox/YellowBox.js:63
    Warning: React has detected a change in the order of Hooks called by WarrantiesHomeButton. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks

       Previous render            Next render
       ------------------------------------------------------
    1. useState                   useContext
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

        in WarrantiesHomeButton
        in Provider
        in View (created by View)
        in View (created by AppContainer)
        in View (created by View)
        in View (created by AppContainer)
        in AppContainer (at src/index.js:26)

  console.error node_modules/react-native/Libraries/YellowBox/YellowBox.js:63
    The above error occurred in the <WarrantiesHomeButton> component:
        in WarrantiesHomeButton
        in Provider
        in View (created by View)
        in View (created by AppContainer)
        in View (created by View)
        in View (created by AppContainer)
        in AppContainer (at src/index.js:26)

    Consider adding an error boundary to your tree to customize error handling behavior.


 FAIL  src/components/home/WarrantiesHomeButton/WarrantiesHomeButton.test.js
  <WarantiesHomeButton/>
    ✓ Should Render correctly (55ms)
    And user is authenticated
      And button is pressed
        ✓ Should show WarrantiesMenu by setting setShowWarrantiesMenu state to true (12ms)
    And user is not authenticated
      And button is pressed
        ✕ Should navigate to signUpScreen (77ms)

  ● <WarantiesHomeButton/> › And user is not authenticated › And button is pressed › Should navigate to signUpScreen

    TypeError: Cannot read property 'length' of undefined

      11 |   const [showWarrantiesMenu, setShowWarrantiesMenu] = useState(false);
      12 | 
    > 13 |   const { warrantiesLoginFlow, user } = useSelector(
         |                                         ^
      14 |     (state) => state.userReducer,
      15 |   );
      16 |   const dispatch = useDispatch();

      at areHookInputsEqual (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5703:38)
      at updateMemo (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6336:11)
      at Object.useMemo (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6703:16)
      at useMemo (node_modules/react/cjs/react.development.js:1592:21)
      at useSelectorWithStoreAndSubscription (node_modules/react-redux/lib/hooks/useSelector.js:31:41)
      at useSelector (node_modules/react-redux/lib/hooks/useSelector.js:117:12)
      at WarrantiesHomeButton (src/components/home/WarrantiesHomeButton/WarrantiesHomeButton.js:13:41)
      at renderWithHooks (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5762:18)
      at updateFunctionComponent (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7579:20)
      at beginWork$1 (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9152:16)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 2 passed, 3 total
Snapshots:   1 passed, 1 total
Time:        4.846s, estimated 5s
Ran all test suites matching /WarrantiesHomeButton/i.

Watch Usage: Press w to show more.
...