【问题标题】:Formik React set values onChange with setFieldValue outside Array of FieldsFormik 在字段数组外使用 setFieldValue 设置值 onChange
【发布时间】:2021-08-19 21:32:19
【问题描述】:

我的目标是为它们嵌套的schedule 对象数组的FieldArray 选择一个StudentonChange 动态setFieldValues

当我选择学生:1 时,我应该为他们的 3 个计划项目中的每一个获取一个字段数组,学生 2:将有示例 4 项目。示例与 older example with Fruit on CodeSandbox 之类的内容有关。 A second CodeSandbox also related for this.

我的问题是,当我尝试 map 一个学生的 schedule 时,它显示 schedule.map 是一个 TypeError。因此不会用要编辑的字段填充我的FieldArray

TypeError: values.schedule.map is not a function

我的 JSON 数据

{
  "count": 2,
  "results": [
    {
      "id": "1",
      "name": "Tom",
      "schedule": [
        {
          "class": "GYM",
          "time": "9:00,
        },
        {
          "class": "History",
          "time": "10:00",
        },
        {
          "class": "Lunch",
          "time": "11:00",
        },
      },
    {
      "id": "2",
      "name": "Nancy",
      "schedule": [
        {
          "class": "Math",
          "time": "9:00,
        },
        {
          "class": "Science",
          "time": "10:00",
        },
        {
          "class": "English",
          "time": "11:00",
        },
        {
          "class": "History",
          "time": "12:00",
        },
      }
    ]
  }

我的 Formik 组件

    const NewStudentSchedule = () => {
      const [studentSchedule, setSchedule] = useState([]);

      useEffect(() => {
        const getSchedule = async () => {
          try {
            const { data } = await fetchContext.authAxios.get(
              `/api/schedule/`
            );
            setSchedule(data.results);
            // console.log(data);
          } catch (err) {
            console.log(err);
          }
        };
        getSchedule();
      }, [fetchContext]);
      
      const initialValues = {
         id: '',
         schedule: [
           {
             class: '',
             time: '',
           },
         ],
       };

    return (
      <Formik
          initialValues={initialValues}
          onSubmit={async (values, { resetForm }) => {
            alert(JSON.stringify(values, null, 2));
            resetForm();
          }}
        >
          {({
            isSubmitting,
            values,
            setFieldValue,
            handleChange,
            errors,
            touched,
          }) => (
            <Form>
              <div className="row">
                <div className="col-md-6 mr-auto">
                  <div className="form-group">
                    <label htmlFor="status">STUDENT</label>
                    <Field
                      className="form-control"
                      as="select"
                      name="id"
                      onChange={(event) => {
                        handleChange(event);
                        const selectedTask = schedule.find(
                          (selectStudent) => selectStudent.id === event.target.value
                        );
                        setFieldValue(
                          `schedule.step`,
                          selectedTask.schedule.step
                        );
                      }}
                    >
                      <option value="" defaultValue disabled>
                        ...
                      </option>
                      {schedule &&
                        schedule.map((i) => (
                          <option key={i.id} value={i.id}>
                            {i.name}
                          </option>
                        ))}
                    </Field>
                  </div>
                </div>
              </div>
              <div className="col-md-12">
                <h3 className="pt-3">CREATE SCHEDULE</h3>
                <FieldArray name="schedule">
                  {({ insert, remove, push }) => (
                    <>
                      {values.schedule.length > 0 &&
                        values.schedule.map((task, index) => (
                          <div className="row" key={index}>
                            <div className="col-11">
                              <div className="row">
                                <div className="col">
                                  <div className="form-group">
                                    <label
                                      htmlFor={`schedule.${index}.class`}
                                    >
                                      CLASS
                                    </label>
                                    <Field
                                      className="form-control"
                                      name={`schedule.${index}.class`}
                                      type="text"
                                    />
                                  </div>
                                </div>
                                <div className="col">
                                  <div className="form-group">
                                    <label
                                      htmlFor={`schedule.${index}.time`}
                                    >
                                      TIME
                                    </label>
                                    <Field
                                      className="form-control"
                                      name={`schedule.${index}.time`}
                                      type="text"
                                    />
                                  </div>
                                </div>  
                              </div>
                            </div>
                            <div className="col-1">
                              <button
                                type="button"
                                className="btn delete"
                                onClick={() => remove(index)}
                              >
                                Delete
                              </button>
                            </div>
                          </div>
                        ))}
                      <button
                        type="button"
                        className="btn add"
                        onClick={() => push({ class: '', time: '' })}
                      >
                        Add
                      </button>
                    </>
                  )}
                </FieldArray>
                <button
                  className="btn float-right mb-5"
                  type="submit"
                  disabled={isSubmitting}
                >
                  SUBMIT
                </button>
              </div>
            </Form>
          )}
        </Formik>

      )

}

  

我的应用程序的屏幕截图:

【问题讨论】:

    标签: reactjs formik


    【解决方案1】:

    这是一个棘手的问题?

    您似乎想使用从 API 获取的数据预填充表单。此外,您希望用户能够在学生(Tom 和 Nancy)之间切换。在这种情况下,您需要在 Formik 的initialValues 中设置所有学生的数据。在处理&lt;FieldArray&gt; 中的班级值时,您需要确保为该特定学生引用正确的班级

    您的代码存在一些问题,例如从未使用过studentSchedule 并且未定义schedule。我继续做了一些假设,并在下面提出了这个解决方案。它通过在&lt;FieldArray&gt; 中使用两个 索引来引用正确的类:selectedStudentIndextaskIndex

    const App = () => {
      const [studentSchedule, setSchedule] = useState([]);
    
      useEffect(() => {
        const getSchedule = async () => {
          try {
            const { data } = await getData();
            setSchedule(data.results);
            // console.log(data);
          } catch (err) {
            console.log(err);
          }
        };
        getSchedule();
      }, []);
    
      return <ScheduleForm students={studentSchedule} />;
    };
    
    const ScheduleForm = ({ students }) => {
      const initialValues = {
        id: "",
        students
      };
    
      return (
        <Formik
          enableReinitialize={true}
          initialValues={initialValues}
          onSubmit={async (values, { resetForm }) => {
            console.log(JSON.stringify(values, null, 2));
          }}
        >
          {({
            isSubmitting,
            values,
            setFieldValue,
            handleChange,
            errors,
            touched
          }) => {
            const selectedStudentIndex = values.students.findIndex(
              ({ id }) => id === values.id
            );
            return (
              <Form>
                <div className="row">
                  <div className="col-md-6 mr-auto">
                    <div className="form-group">
                      <label htmlFor="status">STUDENT</label>
                      <Field
                        className="form-control"
                        as="select"
                        name="id"
                        onChange={(event) => {
                          handleChange(event);
                          const selectedTask = students.find(
                            (selectStudent) =>
                              selectStudent.id === event.target.value
                          );
                          setFieldValue(
                            `schedule.step`,
                            selectedTask.schedule.step
                          );
                        }}
                      >
                        <option value="" defaultValue disabled>
                          ...
                        </option>
                        {values.students &&
                          values.students.map((i) => (
                            <option key={i.id} value={i.id}>
                              {i.name}
                            </option>
                          ))}
                      </Field>
                    </div>
                  </div>
                </div>
                <div className="col-md-12">
                  <h3 className="pt-3">CREATE SCHEDULE</h3>
                  <FieldArray name={`students.${selectedStudentIndex}.schedule`}>
                    {({ insert, remove, push }) => (
                      <div>
                        {values.id !== "" &&
                          values.students[selectedStudentIndex].schedule.map(
                            (task, taskIndex) => (
                              <div className="row" key={taskIndex}>
                                <div className="col-11">
                                  <div className="row">
                                    <div className="col">
                                      <div className="form-group">
                                        <label
                                          htmlFor={`students.${selectedStudentIndex}.schedule.${taskIndex}.class`}
                                        >
                                          CLASS
                                        </label>
                                        <Field
                                          className="form-control"
                                          name={`students.${selectedStudentIndex}.schedule.${taskIndex}.class`}
                                          type="text"
                                        />
                                      </div>
                                    </div>
                                    <div className="col">
                                      <div className="form-group">
                                        <label
                                          htmlFor={`students.${selectedStudentIndex}.schedule.${taskIndex}.time`}
                                        >
                                          TIME
                                        </label>
                                        <Field
                                          className="form-control"
                                          name={`students.${selectedStudentIndex}.schedule.${taskIndex}.time`}
                                          type="text"
                                        />
                                      </div>
                                    </div>
                                  </div>
                                </div>
                                <div className="col-1">
                                  <button
                                    type="button"
                                    className="btn delete"
                                    onClick={() => remove(taskIndex)}
                                  >
                                    Delete
                                  </button>
                                </div>
                              </div>
                            )
                          )}
                        <button
                          type="button"
                          className="btn add"
                          onClick={() => push({ class: "", time: "" })}
                        >
                          Add
                        </button>
                      </div>
                    )}
                  </FieldArray>
                  <button
                    className="btn float-right mb-5"
                    type="submit"
                    disabled={isSubmitting}
                  >
                    SUBMIT
                  </button>
                </div>
              </Form>
            );
          }}
        </Formik>
      );
    };
    
    

    Live Demo

    如果有人想出更简单的方法,我会很感兴趣。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-26
      • 1970-01-01
      • 1970-01-01
      • 2023-02-12
      • 1970-01-01
      • 2022-08-06
      • 2022-08-13
      • 1970-01-01
      相关资源
      最近更新 更多