尝试提交Formik表单时收到此错误。
警告:无法在已卸载的组件上执行React状态更新。 这是空操作,但它表明应用程序中发生内存泄漏。 要修复,请取消useEffect中的所有订阅和异步任务 清理功能。 在Formik中(在layout.tsx:113处) 在div中(由ForwardRef(CardContent)创建) 在ForwardRef(CardContent)中(由WithStyles(ForwardRef(CardContent)创建)) 在WithStyles(ForwardRef(CardContent))中(由Context.Consumer创建) 在StyledComponent中(由Styled(WithStyles(ForwardRef(CardContent))创建)) 在Styled(WithStyles(ForwardRef(CardContent)))中(由CardContent创建) 在CardContent中(由Context.Consumer创建) 在StyledComponent中(由Styled(CardContent)创建) 在Styled(CardContent)中(在layout.tsx:112处) 在div中(由ForwardRef(Paper)创建) 在ForwardRef(Paper)中(由WithStyles(ForwardRef(Paper)创建)) 在WithStyles(ForwardRef(Paper))中(由ForwardRef(Card)创建) 在ForwardRef(Card)中(由WithStyles(ForwardRef(Card)创建)) 在WithStyles(ForwardRef(Card))中(由Context.Consumer创建) 在StyledComponent中(由Styled(WithStyles(ForwardRef(Card))创建)) 在Styled(WithStyles(ForwardRef(Card)))中(由Card创建) 在Card中(在layout.tsx:111处)
函数onSubmit
没有async
调用:
<Formik
...
onSubmit={(values, { setSubmitting }): void => {
setTimeout(() => {
// convert daysOfWeek to Weekday[]
const daysOfWeek = values.daysOfWeek
.filter(day => day.checked)
.map(day => day.dayOfWeek)
const edited: EditTask = { ...task, ...values, daysOfWeek }
onEditTask(edited)
setSubmitting(false)
})
}}
>
onEditTask
回调仅更新TaskItems
的列表。
完整的TaskItem
组件如下所示。 '@web/core...'
组件是我自己的Material UI组件包装。
TaskItem.tsx
import React, { ReactElement } from 'react'
import { useTranslation } from 'react-i18next'
import Grid from '@material-ui/core/Grid'
import ListItemIcon from '@material-ui/core/ListItemIcon'
import ListItemText from '@material-ui/core/ListItemText'
import CloseIcon from '@material-ui/icons/Close'
import Typography from '@web/core/components/Typography'
import MenuButton from '@web/core/components/MenuButton'
import MenuItem from '@web/core/components/MenuItem'
import TextField from '@web/core/components/TextField'
import Checkbox from '@web/core/components/Checkbox'
import Button from '@web/core/components/Button'
import Card from '@web/core/components/Card'
import EditIcon from '@web/core/theme/icons/Edit'
import { TaskSchedule, Weekday } from 'stores/goals/models'
import {
EditTask,
getDistinctTaskSchedulesSorted,
} from 'components/CitizenDetails/DietRules/FormDrawer'
import { TaskItemViewMode } from 'components/CitizenDetails/DietRules/TaskItem'
import { Formik, FieldArray, Form } from 'formik'
import uuid from 'uuid/v4'
import * as Yup from 'yup'
import TaskOverview from '../TaskOverview'
import { DeleteIcon, DeleteMenuItemText, EditCardContent, RemoveScheduleButton } from './styled'
const taskValidationSchema = Yup.object().shape({
subject: Yup.string().required('Required'),
description: Yup.string().nullable(),
daysOfWeek: Yup.array()
.min(1, 'Min 1 day')
.required('Required'),
taskSchedules: Yup.array()
.ensure()
.min(0, 'Min 0 elements'),
})
interface Props {
viewMode: TaskItemViewMode
task: EditTask
onChangeViewMode: (viewMode: TaskItemViewMode) => void
onDeleteTask: () => void
onEditTask: (task: EditTask) => void
disableMenu?: boolean
}
export interface CheckedWeekday {
checked: boolean
dayOfWeek: Weekday
}
function mapToCheckedWeekday(weekday: Weekday, checked: boolean): CheckedWeekday {
return {
dayOfWeek: weekday,
checked,
}
}
export default function TaskItem({
viewMode,
task,
onChangeViewMode,
onDeleteTask,
onEditTask,
disableMenu,
}: Props): ReactElement {
const [t] = useTranslation()
type TaskFormValues = Pick<EditTask, 'subject' | 'description'> & {
daysOfWeek: CheckedWeekday[]
taskSchedules: TaskSchedule[]
}
const initialValues: TaskFormValues = {
...task,
daysOfWeek: Object.values(Weekday).map(day =>
mapToCheckedWeekday(day, task.daysOfWeek.includes(day))
),
taskSchedules: getDistinctTaskSchedulesSorted(task.taskSchedules),
}
return (
<>
{viewMode === TaskItemViewMode.View ? (
<Grid container justify="space-between" alignItems="center">
<Grid item>
<TaskOverview task={task} />
</Grid>
<Grid item>
{!disableMenu && (
<MenuButton id="diet-task-overview-menu-button">
<MenuItem onClick={(): void => onChangeViewMode(TaskItemViewMode.Edit)}>
<ListItemIcon>
<EditIcon />
</ListItemIcon>
<ListItemText primary={t('edit')} />
</MenuItem>
<MenuItem key="diet-task-overview-menu-remove-button" onClick={onDeleteTask}>
<ListItemIcon>
<DeleteIcon />
</ListItemIcon>
<DeleteMenuItemText primary={t('remove')} />
</MenuItem>
</MenuButton>
)}
</Grid>
</Grid>
) : (
<Card>
<EditCardContent>
<Formik
initialValues={initialValues}
validationSchema={taskValidationSchema}
onSubmit={(values, { setSubmitting }): void => {
setTimeout(() => {
// convert daysOfWeek to Weekday[]
const daysOfWeek = values.daysOfWeek
.filter(day => day.checked)
.map(day => day.dayOfWeek)
const edited: EditTask = { ...task, ...values, daysOfWeek }
onEditTask(edited)
setSubmitting(false)
})
}}
>
{({
values,
errors,
isValid,
touched,
dirty,
handleChange,
handleBlur,
handleSubmit,
handleReset,
isSubmitting,
validateForm,
}): ReactElement => (
<Form>
<Grid container direction="column" spacing={3}>
<Grid item>
<Typography variant="h6">{t('goals:diet.task.title')}</Typography>
</Grid>
<Grid item>
<TextField
id={`task-${task.uuid}-subject`}
label={t('title')}
name="subject"
onChange={handleChange}
onBlur={handleBlur}
value={values.subject}
fullWidth
inputProps={{ autoFocus: viewMode === TaskItemViewMode.Create }}
/>
{errors.subject && touched.subject && errors.subject}
</Grid>
<Grid item>
<TextField
id={`task-${task.uuid}-description`}
label={t('description')}
name="description"
onChange={handleChange}
onBlur={handleBlur}
value={values.description}
rows="3"
multiline
fullWidth
/>
</Grid>
<Grid item>
<Typography variant="subtitle1" gutterBottom>
{t('day').toUpperCase()}
</Typography>
<FieldArray
name="daysOfWeek"
render={({ replace }) => (
<Grid container spacing={2}>
{values.daysOfWeek.map((day, idx) => (
<Grid item key={`task-weekday-${day.dayOfWeek}`}>
<Checkbox
id={`task-weekday-checkbox-${day.dayOfWeek}`}
name={`daysOfWeek.${idx}.dayOfWeek`}
value={day.dayOfWeek}
checked={day.checked}
label={t(`weekdays.${day.dayOfWeek.toLowerCase()}`, {
context: 'short',
})}
onChange={e => {
replace(idx, { ...day, checked: !day.checked })
}}
/>
</Grid>
))}
</Grid>
)}
/>
</Grid>
<FieldArray
name="taskSchedules"
render={({ remove, replace, push }) => (
<>
<Grid item>
<Typography variant="subtitle1" gutterBottom>
{t('schedule_plural').toUpperCase()}
</Typography>
{values.taskSchedules.map((schedule, idx) => (
<Grid
container
spacing={6}
key={`task-weekday-schedule-${schedule.uuid}`}
>
<Grid item>
<TextField
type="time"
key={`task-schedule-${schedule.uuid}`}
id={`task-schedule-${schedule.uuid}`}
label={t('time')}
name={`taskSchedules.${idx}.time`}
value={schedule.time}
onChange={e => {
const time = e.target.value
replace(idx, { ...schedule, time })
}}
inputProps={{
step: 300, // 5 min
}}
/>
</Grid>
<Grid item>
<RemoveScheduleButton
id={`task-weekday-button-remove-schedule-${schedule.uuid}`}
vanilla
icon
onClick={(): void => {
remove(idx)
// bug in formik makes this necessary
// see https://github.com/jaredpalmer/formik/issues/784#issuecomment-503135849
setTimeout(() => {
validateForm()
}, 10)
}}
>
<CloseIcon />
</RemoveScheduleButton>
</Grid>
</Grid>
))}
</Grid>
<Grid item>
<Button
id="task-weekday-button-add-schedule"
ghost
onClick={(): void => {
push({
time: '00:00:00',
taskUuid: task.uuid,
uuid: uuid(),
dayOfWeek: Weekday.Monday, // temporary value
})
}}
>
{t('goals:diet.task.add-schedule')}
</Button>
</Grid>
</>
)}
/>
<Grid item>
<Grid container justify="flex-end" spacing={2}>
<Grid item>
<Button
id="task-button-cancel-editing"
size="small"
ghost
licorice
onClick={
viewMode === TaskItemViewMode.Create
? onDeleteTask
: (): void => {
handleReset()
onChangeViewMode(TaskItemViewMode.View)
}
}
>
{t('cancel')}
</Button>
</Grid>
<Grid item>
<Button
type="submit"
id="task-button-save-editing"
size="small"
disabled={!dirty || !isValid || isSubmitting}
>
{t('ok')}
</Button>
</Grid>
</Grid>
</Grid>
</Grid>
</Form>
)}
</Formik>
</EditCardContent>
</Card>
)}
</>
)
}
答案 0 :(得分:1)
onEditTask
可能正在更改viewMode
,从而删除了<EditCardContent>
,因此在对setSubmitting
的调用发生时,Formik已经被卸载。