#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 либо нет массива зависимостей, либо одна из зависимостей изменяется при каждом рендеринге.