You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React编辑页面初始值不显示,刷新后恢复问题排查

React编辑页面首次加载数据不显示问题修复

问题描述

开发React编辑页面时,通过URL参数id从数据库查询数据,预期数据会填充到表单输入组件中,但首次进入页面时数据不显示,刷新页面后才正常加载。已添加错误处理逻辑,但未触发生效。

问题根源

  1. React Query缓存未区分不同ID:查询班级数据的queryKey仅为["classData"],未包含动态的classId,导致路由切换到不同ID时,React Query复用旧缓存数据,首次加载展示错误内容。
  2. Formik未监听外部数据变化:Formik的initialValues仅在组件初始化时赋值一次,当classData异步加载完成后,Formik不会自动更新表单值,导致表单仍为空。
  3. 错误处理未展示具体信息:当前错误提示为固定文本,无法定位具体失败原因。
  4. 教师数据查询错误文案有误:捕获错误时错误信息仍标注为“class data”,与实际查询资源不符。

修复方案

1. 优化React Query查询键

给班级数据的queryKey添加classId,确保每个ID对应独立缓存条目:

{
  queryKey: ["classData", classId], // 新增classId区分不同查询
  queryFn: async () => {
    try {
      const data = await fetchData(`class/${classId}`);
      return data;
    } catch (error) {
      throw new Error(`Failed to fetch class data: ${error.message}`);
    }
  },
}

2. 让Formik支持重新初始化

在Formik组件中添加enableReinitialize={true},同时给classData属性添加可选链操作符,避免数据未加载时出现undefined报错:

<Formik
  initialValues={{
    className: classData?.className || "",
    division: classData?.division || "",
    batch: classData?.batch || "",
    fees: classData?.fees || "",
    subjects: classData?.subjects || [],
    teacherId: classData?.teacherId || "",
  }}
  enableReinitialize={true} // 开启后,initialValues变化时自动更新表单
  // ...其他配置
>

3. 完善错误提示

将错误提示改为展示具体错误信息,方便定位问题:

{classError && <Error severity="error">{classError.message}</Error>}

4. 修正教师数据查询的错误文案

把教师数据查询的错误提示文案修正为对应资源:

{
  queryKey: ["teacherData"],
  queryFn: async () => {
    try {
      const data = await fetchData("teacher/get-all");
      return data;
    } catch (error) {
      throw new Error(`Failed to fetch teacher data: ${error.message}`); // 修正为teacher data
    }
  },
}

完整修改后的组件代码

// react imports
import { useParams } from "react-router-dom";

// material-ui
import {
  Button,
  FormHelperText,
  Grid,
  InputLabel,
  OutlinedInput,
  Stack,
  CircularProgress,
  Select,
  MenuItem,
  LinearProgress,
} from "@mui/material";

// third party
import * as Yup from "yup";
import { Formik, FieldArray } from "formik";
import axios from "axios";
import { useQueries } from "@tanstack/react-query";

// project import
import AnimateButton from "components/@extended/AnimateButton";
import { base_url } from "utils/baseurl";
import { fetchData } from "utils/fetchData";
import Error from "utils/Error";
import { useNavigate } from "react-router-dom";
import Progress from "utils/Progress";

// ============================|| CLASS - EDIT FORM ||============================ //

const ClassEdit = () => {
  const { id: classId } = useParams();
  const navigate = useNavigate();
  const [classResult, teacherResult] = useQueries({
    queries: [
      {
        queryKey: ["classData", classId], // 添加classId区分不同查询
        queryFn: async () => {
          try {
            const data = await fetchData(`class/${classId}`);
            return data;
          } catch (error) {
            throw new Error(`Failed to fetch class data: ${error.message}`);
          }
        },
      },
      {
        queryKey: ["teacherData"],
        queryFn: async () => {
          try {
            const data = await fetchData("teacher/get-all");
            return data;
          } catch (error) {
            throw new Error(`Failed to fetch teacher data: ${error.message}`); // 修正错误文案
          }
        },
      },
    ],
  });
  const { data: classData, error: classError, isPending: classIsPending } = classResult;
  const { data: teacherData, error: teacherError, isPending: teacherIsPending } = teacherResult;

  return (
    <>
      {classError && <Error severity="error">{classError.message}</Error>} {/* 展示具体错误信息 */}
      {classIsPending ? (
        <Progress />
      ) : (
        <Formik
          initialValues={{
            className: classData?.className || "",
            division: classData?.division || "",
            batch: classData?.batch || "",
            fees: classData?.fees || "",
            subjects: classData?.subjects || [],
            teacherId: classData?.teacherId || "",
          }}
          enableReinitialize={true} // 开启表单重新初始化
          validationSchema={Yup.object().shape({
            className: Yup.number(),
            division: Yup.string().max(255),
            batch: Yup.number(),
            teacherId: Yup.string(),
            fees: Yup.number(),
            subjects: Yup.array(),
          })}
          onSubmit={async (values, { setErrors, setStatus, setSubmitting }) => {
            try {
              const response = await axios.put(`${base_url}/class/${classId}`, values);
              if (!response.data.success) setErrors({ submit: response.data.message });
              else navigate(`/class`);

              setStatus({ success: false });
              setSubmitting(false);
            } catch (err) {
              console.error(err);
              setStatus({ success: false });
              setErrors({ submit: err.message });
              setSubmitting(false);
            }
          }}
        >
          {({ errors, handleBlur, handleChange, handleSubmit, isSubmitting, touched, values }) => (
            <form noValidate onSubmit={handleSubmit}>
              <Grid container spacing={3}>
                <Grid item xs={12} md={6}>
                  <Stack spacing={1}>
                    <InputLabel htmlFor="class-name">Class Standard</InputLabel>
                    <OutlinedInput
                      fullWidth
                      id="class-name"
                      value={values.className}
                      name="className"
                      onBlur={handleBlur}
                      onChange={handleChange}
                      error={Boolean(touched.className && errors.className)}
                    />
                    {touched.className && errors.className && (
                      <FormHelperText error id="helper-text-className-signup">
                        {errors.className}
                      </FormHelperText>
                    )}
                  </Stack>
                </Grid>
                <Grid item xs={12} md={6}>
                  <Stack spacing={1}>
                    <InputLabel htmlFor="division">Division</InputLabel>
                    <OutlinedInput
                      fullWidth
                      error={Boolean(touched.division && errors.division)}
                      id="division"
                      value={values.division}
                      name="division"
                      onBlur={handleBlur}
                      onChange={handleChange}
                    />
                    {touched.division && errors.division && (
                      <FormHelperText error id="helper-text-division-signup">
                        {errors.division}
                      </FormHelperText>
                    )}
                  </Stack>
                </Grid>
                <Grid item xs={6}>
                  <Stack spacing={1}>
                    <InputLabel htmlFor="teacherId">Teacher</InputLabel>
                    <Select
                      fullWidth
                      id="teacherId"
                      value={values.teacherId}
                      name="teacherId"
                      onChange={handleChange}
                      onBlur={handleBlur}
                      error={touched.teacherId && errors.teacherId}
                    >
                      {teacherError && <MenuItem key="error">Cannot find teacher data</MenuItem>}
                      {teacherIsPending ? (
                        <LinearProgress />
                      ) : (
                        teacherData?.map((teacher) => (
                          <MenuItem key={teacher._id} value={teacher._id}>
                            {teacher.name}
                          </MenuItem>
                        ))
                      )}
                    </Select>
                    {touched.teacherId && errors.teacherId && (
                      <FormHelperText error id="helper-text-teacherId-signup">
                        {errors.teacherId}
                      </FormHelperText>
                    )}
                  </Stack>
                </Grid>

                <Grid item xs={6}>
                  <Stack spacing={1}>
                    <InputLabel htmlFor="batch">Batch Start</InputLabel>
                    <OutlinedInput
                      fullWidth
                      error={Boolean(touched.batch && errors.batch)}
                      id="batch"
                      value={values.batch}
                      name="batch"
                      type="number"
                      onBlur={handleBlur}
                      onChange={handleChange}
                      placeholder="2019"
                      inputProps={{}}
                    />
                    {touched.batch && errors.batch && (
                      <FormHelperText error id="helper-text-batch-signup">
                        {errors.batch}
                      </FormHelperText>
                    )}
                  </Stack>
                </Grid>

                <Grid item xs={6}>
                  <Stack spacing={1}>
                    <InputLabel htmlFor="fees">Fees</InputLabel>
                    <OutlinedInput
                      fullWidth
                      error={Boolean(touched.fees && errors.fees)}
                      id="fees"
                      value={values.fees}
                      name="fees"
                      type="number"
                      onBlur={handleBlur}
                      onChange={handleChange}
                      inputProps={{}}
                    />
                    {touched.fees && errors.fees && (
                      <FormHelperText error id="helper-text-fees-signup">
                        {errors.fees}
                      </FormHelperText>
                    )}
                  </Stack>
                </Grid>
                <Grid item xs={6}>
                  <Stack spacing={1} sx={{ mt: "8px" }}>
                    <FieldArray
                      name="subjects"
                      render={(arrayHelpers) => (
                        <div>
                          {values.subjects &&
                            values.subjects.map((subject, index) => (
                              <div key={index}>
                                <InputLabel htmlFor={`subjects.${index}`}>Subject</InputLabel>
                                <OutlinedInput
                                  fullWidth
                                  id={`subjects.${index}`}
                                  value={values.subjects[index]}
                                  name={`subjects.${index}`}
                                  onBlur={handleBlur}
                                  onChange={handleChange}
                                />
                                <Button type="button" onClick={() => arrayHelpers.remove(index)}>
                                  Remove
                                </Button>
                              </div>
                            ))}
                          <Button type="button" onClick={() => arrayHelpers.push("")}>
                            Add
                          </Button>
                        </div>
                      )}
                    />
                  </Stack>
                </Grid>
                <Grid item xs={12}>
                  <AnimateButton>
                    <Button
                      disableElevation
                      disabled={isSubmitting}
                      size="large"
                      type="submit"
                      variant="contained"
                      color="primary"
                    >
                      Edit
                    </Button>
                  </AnimateButton>
                </Grid>
              </Grid>
            </form>
          )}
        </Formik>
      )}
    </>
  );
};

export default ClassEdit;

额外注意点

  • 检查fetchData函数是否正确解析API响应,比如是否需要从response.data中提取数据主体(例如return data.data)。
  • 确保路由配置中正确定义了参数路径,比如path="/class/edit/:id"。

内容的提问来源于stack exchange,提问作者farismamnoon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 05:44:51