我是React Hooks的新手,并且正在迈出第一步...感谢您的帮助!我想在呈现图表之前重用逻辑对数据集进行排序和转换。所以我将其拆分为“自定义”钩子,但收到警告,它似乎处于重新渲染循环中(缓慢向上计数)
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.
我应该有一个依赖项数组,并且依赖项只能在单击按钮时更改。.所以我不明白为什么它会进入重新渲染循环...?
CigarettesDetailsContainer
接收道具中的“原始”数据,并将转换后的数据传递给呈现图表的子组件。它还处理来自孩子的更改日期,因此我将其保留在此处。
useSingleValueChartData
挂钩可转换原始数据,并且在更改日期和时间段时应重新运行。
香烟详情容器
import React, { FC, useState } from 'react'
import moment from 'moment'
import { ApiRegistration } from 'models/Api/ApiRegistration'
import { CigarettesDetails } from './layout'
import { useSingleValueChartData } from 'hooks/useSingleValueChartData'
import { TimePeriod } from 'models/TimePeriod'
interface Props {
registrations: ApiRegistration[]
}
const initialStart = moment()
.year(2018)
.week(5)
.startOf('isoWeek')
const initialEnd = initialStart.clone().add(1, 'week')
const initialPeriod = TimePeriod.Week
const CigarettesDetailsContainer: FC<Props> = ({ registrations }) => {
const [startDate, setStartDate] = useState(initialStart)
const [endDate, setEndDate] = useState(initialEnd)
const [timePeriod, setTimePeriod] = useState(initialPeriod)
const data = useSingleValueChartData(
registrations,
startDate.toDate(),
endDate.toDate(),
timePeriod
)
const handleTimeChange = (change: number) => {
let newStartDate = startDate.clone()
let newEndDate = endDate.clone()
switch (timePeriod) {
default:
newStartDate.add(change, 'week')
newEndDate.add(change, 'week')
break
}
setStartDate(newStartDate)
setEndDate(newEndDate)
}
return <CigarettesDetails onTimeChange={handleTimeChange} data={data} />
}
export default CigarettesDetailsContainer
useSingleValueChartData
import React, { useEffect, useState } from 'react'
import moment from 'moment'
import { ApiRegistration } from 'models/Api/ApiRegistration'
import { TimePeriod } from 'models/TimePeriod'
import { GroupedChartData, SingleValueChartData } from 'models/ChartData'
import { createWeekdaysList } from 'components/Core/Utils/dateUtils'
export function useSingleValueChartData(
registrations: ApiRegistration[],
startDate: Date,
endDate: Date,
timePeriod: TimePeriod = TimePeriod.Week
) {
const [data, setData] = useState<SingleValueChartData[]>([])
// used for filling chart data set with days without registrations
let missingWeekDays: string[] = []
useEffect(() => {
// which days are missing data
// eslint-disable-next-line react-hooks/exhaustive-deps
missingWeekDays = createWeekdaysList(startDate)
const filteredByDates: ApiRegistration[] = registrations.filter(reg =>
moment(reg.date).isBetween(startDate, endDate)
)
const filteredByDirtyValues = filteredByDates.filter(reg => reg.value && reg.value > -1)
const grouped: SingleValueChartData[] = Object.values(
filteredByDirtyValues.reduce(groupByWeekDay, {} as GroupedChartData<
SingleValueChartData
>)
)
const filled: SingleValueChartData[] = grouped.concat(fillInMissingDays())
const sorted: SingleValueChartData[] = filled.sort(
(a: SingleValueChartData, b: SingleValueChartData) =>
new Date(a.date).getTime() - new Date(b.date).getTime()
)
setData(sorted)
}, [startDate, timePeriod])
function groupByWeekDay(
acc: GroupedChartData<SingleValueChartData>,
{ date: dateStr, value }: { date: string; value?: number }
): GroupedChartData<SingleValueChartData> {
const date: string = moment(dateStr).format('YYYY-MM-DD')
acc[date] = acc[date] || {
value: 0,
}
acc[date] = {
date,
value: value ? acc[date].value + value : acc[date].value,
}
// remove day from list of missing week days
const rest = missingWeekDays.filter(d => d !== date)
missingWeekDays = rest
return acc
}
function fillInMissingDays(): SingleValueChartData[] {
return missingWeekDays.map(date => {
return {
value: 0,
date,
}
})
}
return data
}
答案 0 :(得分:0)
在自定义挂钩中,尽管您只想在更改startDate或timePeriod时运行效果,但目前每次都运行效果。
这是因为如何将startDate
和endDate
参数传递给自定义钩子。
const data = useSingleValueChartData(
registrations,
startDate.toDate(),
endDate.toDate(),
timePeriod
)
.toDate
返回新的日期对象。
因此,每次将新的日期对象传递给自定义钩子。
要解决此问题,请将startDate
和endDate
直接传递(即不使用toDate
)到自定义钩子,并在自定义钩子中管理当前日期转换。