Реагировать предотвращать ошибку превышения максимальной глубины обновления в динамической форме

#reactjs #typescript

Вопрос:

Я пытаюсь создать динамический фильтр для фильтрации отображаемых данных.

Вот код главной страницы :

 import { FunctionComponent, useState } from "react";
import { TenantsTab } from "..";
import { TenantType, UnpaidRent } from "../../types";
import TenantsSelects from "../TenantsSelects";

const TenantsManagement: FunctionComponent = () => {

const unpaidRent1:UnpaidRent = {id:0, date:"02/03/2021"}
const unpaidRent2:UnpaidRent = {id:1, date:"03/05/2021"}
const tenant1:TenantType = { id:0, firstName:"AAAAA", lastName:"AAAA", floorNb:1, buildingNb:1, familyStatus:"Single", workingStatus:"Worker"};
const tenant2:TenantType = { id:1, firstName:"BBB", lastName:"BBBB", unpaidRent:unpaidRent1, floorNb:2, buildingNb:1, familyStatus:"Couple", workingStatus:"Student"};
const tenant3:TenantType = { id:2, firstName:"CCCCCCC", lastName:"CCCC", floorNb:3, buildingNb:3, familyStatus:"Single", workingStatus:"Not working"};
const tenant4:TenantType = { id:3, firstName:"DDDD", lastName:"DDDDD", unpaidRent:unpaidRent2, floorNb:2, buildingNb:2, familyStatus:"Collocation", workingStatus:"Worker"};
const tenant5:TenantType = { id:4, firstName:"EEEE", lastName:"EEEE", floorNb:2, buildingNb:2, familyStatus:"Collocation", workingStatus:"Worker"};
const tenants:TenantType[] = [tenant1, tenant2, tenant3, tenant4, tenant5]
const [data, setData] = useState(tenants)

return (
    <div className="container">
        <div className="jumbotron jumbotron-fluid">
            <div className="container">
                <p className="lead">Tenants List</p>
            </div>
        </div>
        <TenantsSelects 
            data={tenants} 
            setParentData={setData} 
        />
        <TenantsTab tenants={data}/>
    </div>
)
}

export default TenantsManagement;
 

В этом примере TenantsTab является компонентом, ответственным за визуализацию данных, в то время как TenantsSelect отвечает за фильтрацию данных.

Вот компонент TenantsTab

 import { FunctionComponent } from 'react';
import { TenantTabRow } from '../../components';
import { TenantType } from '../../types';

type props ={
  tenants:TenantType[]
}

const TenantsTab: FunctionComponent<props> = ({tenants}:props) => {
return (
    <div className="list-group">
        {
            tenants.map(x=>{
                return <TenantTabRow tenant={x} />
            })
        }
    </div>
)
}

export default TenantsTab;
 

И вот арендаторам сначала нужно выбрать компонент:

 import { FunctionComponent, useState, useEffect } from "react";
import { Link } from "react-router-dom";
 import { TenantType } from "../../types";
import { CustomSelect } from "../../components";

type props = {
data: TenantType[],
setParentData: Function,
}

 const TenantsSelects: FunctionComponent<props> = ({ data, setParentData }: props) => {

const [floor, setFloor] = useState('N°')
const [building, setBuilding] = useState('N°')
const [familySituation, setFamilySituation] = useState('N°')
const [rent, setRent] = useState('status')
const [workingStatus, setWorkingStatus] = useState('situation')

const handleChange = (()=>{})

useEffect(() => {
    const floors = floor === 'N°' ? data : data.filter(x => x.floorNb === Number(floor))
    const buildings = building === 'N°' ? data : data.filter(x => x.buildingNb === Number(building))
    const familyStates = familySituation === 'N°' ? data : data.filter(x => x.familyStatus === familySituation)
    const rents = rent === 'status' ? data : rent === 'Unpaid' ? data.filter(x => x.unpaidRent !== undefined) : rent === 'paid' ? data.filter(x => x.unpaidRent === undefined) : data
    const workingStatuss = workingStatus === 'situation' ? data : data.filter(x => x.workingStatus === workingStatus)
    const res = [rents, buildings, floors, familyStates, workingStatuss]
    setParentData(res.reduce((a, b) => a.filter(c => b.includes(c))))
},[floor, familySituation, building, workingStatus, rent, data, setParentData])

return (
    <div className="form-row">
        <CustomSelect title={"Floor N°"} options={['N°', '1', '2', '3']} setData={setFloor} />
        <CustomSelect title={"Building N°"} options={['N°', '1', '2', '3']} setData={setBuilding} />
        <CustomSelect title={"Family Situation"} options={['N°', 'Couple', 'Single', 'Collocation']} setData={setFamilySituation} />
        <CustomSelect title={"Rent Status"} options={['status', 'Unpaid', 'paid']} setData={setRent} />
        <CustomSelect title={"sociale"} options={['situation', 'Worker', 'Student', 'Not working']} setData={setWorkingStatus} />
    </div>
)
}

export default TenantsSelects
 

Это сработало и делает фильтрацию реактивной, но вызывает следующую ошибку :

 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.
 

Поэтому я попытался исправить эту ошибку, завернув код в хук useCallback, что привело к следующему :

 import { FunctionComponent, useState, useEffect, useCallback } from "react";
import { Link } from "react-router-dom";
 import { TenantType } from "../../types";
import { CustomSelect } from "../../components";

type props = {
data: TenantType[],
 setParentData: Function,
 }

const TenantsSelects: FunctionComponent<props> = ({ data, setParentData }: props) => {

const [floor, setFloor] = useState('N°')
const [building, setBuilding] = useState('N°')
const [familySituation, setFamilySituation] = useState('N°')
const [rent, setRent] = useState('status')
const [workingStatus, setWorkingStatus] = useState('situation')
const [value, setValue] = useState(data)

const handleChange = useCallBack(() => {
const floors = floor === 'N°' ? data : data.filter(x => x.floorNb === Number(floor))
const buildings = building === 'N°' ? data : data.filter(x => x.buildingNb === Number(building))
const familyStates = familySituation === 'N°' ? data : data.filter(x => x.familyStatus === familySituation)
const rents = rent === 'status' ? data : rent === 'Unpaid' ? data.filter(x => x.unpaidRent !== undefined) : rent === 'paid' ? data.filter(x => x.unpaidRent === undefined) : data
const workingStatuss = workingStatus === 'situation' ? data : data.filter(x => x.workingStatus === workingStatus)
const res = [rents, buildings, floors, familyStates, workingStatuss]
setValue(res.reduce((a, b) => a.filter(c => b.includes(c))))
},[floor, familySituation, building, workingStatus, rent, data])

useEffect(() => {
    handleChange()
    setParentData(value)
},[value, setParentData, handleChange])

return (
<div className="form-row">
    <CustomSelect title={"Floor N°"} options={['N°', '1', '2', '3']} setData={setFloor} />
    <CustomSelect title={"Building N°"} options={['N°', '1', '2', '3']} setData={setBuilding} />
    <CustomSelect title={"Family Situation"} options={['N°', 'Couple', 'Single', 'Collocation']} setData={setFamilySituation}/>
    <CustomSelect title={"Rent Status"} options={['status', 'Unpaid', 'paid']} setData={setRent} />
    <CustomSelect title={"Status"} options={['situation', 'Worker', 'Student', 'Not working']} setData={setWorkingStatus} />
</div>
)
}
export default TenantsSelects
 

Это также не работает, так как ошибка все еще запускается. Я не знаю, что я делаю не так. Я попытался отфильтровать данные по значению крючка, но это привело к уничтожению данных.

Спасибо за помощь.

Комментарии:

1. setParentData(значение) внутри обратного вызова.

2. Привет, это вызывает ту же ошибку : Предупреждение: Превышена максимальная глубина обновления. Это может произойти, когда компонент вызывает setState внутри useEffect, но у useEffect либо нет массива зависимостей, либо одна из зависимостей изменяется при каждом рендеринге.