React компонент перерисовывает бесконечно - PullRequest
0 голосов
/ 15 января 2020

Во-первых, я действительно новичок, чтобы реагировать; Итак, извините, для начинающих вопросов.

У меня есть приложение React с Redux и Redux Saga.

Один из компонентов выглядит так:

import { TableContainer, TableHead, TableRow } from '@material-ui/core';
import Paper from '@material-ui/core/Paper';
import makeStyles from '@material-ui/core/styles/makeStyles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { ProgramCategory } from '../model/program-category';
import { ProgramCategoryItemRow } from '../ProgramGategoryItemRow/ProgramCategoryItemRow';
import { ProgramCategoryActions } from '../store/program-category.actions';
import { ProgramCategorySelectors } from '../store/program-category.selectors';

const useStyles = makeStyles({
  table: {
    width: '100%',
  },
  tableHeadCell: {
    fontWeight: 'bold',
  },
});

export interface ProgramCategoriesTableProps {
  isLoaded: boolean;
  categories: ProgramCategory[];
  fetchAllCategories: () => void;
}

export const PureProgramCategoriesTable: React.FC<ProgramCategoriesTableProps> = ({
  isLoaded,
  categories,
  fetchAllCategories,
}) => {
  useEffect(() => {
    console.error('in useEffect');
    fetchAllCategories();
  });

  const styles = useStyles();

  return (
    <TableContainer component={Paper}>
      // the rest
      <TableBody>
          {categories.map(c => (
            <ProgramCategoryItemRow category={c} />
          ))}
      </TableBody>
    </TableContainer>
  );
};

const mapStateToProps = createSelector(
  [ProgramCategorySelectors.isLoaded, ProgramCategorySelectors.getAll],
  (isLoaded, categories) => ({ isLoaded, categories }),
);

const mapDispatchToProps = {
  fetchAllCategories: ProgramCategoryActions.fetchAll.start,
};

export const ProgramCategoriesTable = connect(mapStateToProps, mapDispatchToProps)(PureProgramCategoriesTable);

Саги этот процесс ProgramCategoryActions.fetchAll.start выглядит следующим образом:

import { call, put, takeLatest } from 'redux-saga/effects';
import { ProgramCategoryApi } from '../services/program-category.api';
import { ProgramCategoryActions } from './program-category.actions';

function* handleFetchAll() {
  try {
    const categories = yield call(ProgramCategoryApi.fetchAll);
    yield put(ProgramCategoryActions.fetchAll.success(categories));
  } catch (e) {
    yield put(ProgramCategoryActions.fetchAll.failure(e));
  }
}

export function* programCategorySagas() {
  yield takeLatest(ProgramCategoryActions.fetchAll.start.type, handleFetchAll);
}

Все имеет смысл, но что происходит, мой код действия выполняется снова и снова. Углубившись в это немного больше, кажется, что ловушка эффекта также выполняется снова и снова. Если я правильно понимаю, это происходит из-за того, что данные в состоянии меняются, компонент снова перерисовывается. Но это приводит к бесконечному l oop. Что я делаю неправильно? Как правильно настроить этот тип компонента?

Один из найденных вариантов - изменить сагу на:

function* handleFetchAll() {
  try {
    const alreadyLoaded = select(ProgramCategorySelectors.isLoaded);
    if (!alreadyLoaded) {
      const categories = yield call(ProgramCategoryApi.fetchAll);
      yield put(ProgramCategoryActions.fetchAll.success(categories));
    }
  } catch (e) {
    yield put(ProgramCategoryActions.fetchAll.failure(e));
  }
}

Итак, он вызывает API только один раз; и, кажется, работает нормально таким образом. Но правильное ли это решение?

Как предлагается в комментариях, я попытался добавить зависимость к эффекту:

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

Теперь я получаю сообщение об ошибке:

. / Src / program / ProgramCategoriesTable / ProgramCategoriesTable.tsx Строка 37: 6: React Hook useEffect отсутствует зависимость: 'fetchAllCategories'. Либо включите его, либо удалите массив зависимостей. Если 'fetchAllCategories' меняется слишком часто, найдите родительский компонент, который его определяет, и добавьте это определение в useCallback response-hooks / исчерпывающее-deps

1 Ответ

0 голосов
/ 15 января 2020

Проблема здесь,

useEffect(() => {
  console.error('in useEffect');
  fetchAllCategories();
});

Из реагирующих документов: запускается ли useEffect после каждого рендера? Да! По умолчанию он запускается как после первого рендера, так и после каждого обновления. (Позже мы поговорим о том, как это настроить.) Вместо того, чтобы думать в терминах «монтирования» и «обновления», вам может показаться, что вам будет легче думать, что эффекты происходят «после рендеринга». React гарантирует, что DOM был обновлен к моменту запуска эффектов.

https://reactjs.org/docs/hooks-effect.html

В конце необходимо передать и массив зависимостей.

useEffect(() => {
  console.error('in useEffect');
  fetchAllCategories();
}, []);

Надеюсь, это поможет!

...