【发布时间】:2019-10-03 09:58:08
【问题描述】:
我是 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 在 props 中接收“原始”数据,并将转换后的数据传递给渲染图表的子组件。它还处理来自孩子的更改日期,因此我将状态保留在这里。
useSingleValueChartData 挂钩转换原始数据,并在日期和时间段发生更改时重新运行。
CigarettesDetailsContainer
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
使用SingleValueChartData
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
}
【问题讨论】:
标签: reactjs react-hooks