【问题标题】:Get values from nested forms using final form in react/typescript使用 react/typescript 中的最终形式从嵌套形式中获取值
【发布时间】:2020-06-02 15:45:35
【问题描述】:

我无法使用最终表单从嵌套表单中获取值。

这是我的 index.tsx

import React, { useState, ChangeEvent } from 'react';
import { Form } from 'react-final-form';
import {
  Box, Typography, Button, IconButton, Grid, FormControl, InputLabel, Select,
} from '@material-ui/core';
import AddCircleIcon from '@material-ui/icons/AddCircle';
import FieldInput from 'forms/shared/fields/input';
import FieldFileUploader from 'forms/shared/fields/file-uploader';
import FieldCheckbox from 'forms/shared/fields/checkbox';
import FormRadioQuestions from './partials/form-radio';
import FormExperience from './partials/form-experience';
import FormEducation from './partials/form-education';
import FormPersonalInfo from './partials/form-personal-info';
import FormGovernmentIds from './partials/form-government-id';
import ItemExperience from './partials/experience-item';
import ItemEducation from './partials/education-item';
import useStyles from './styles';

const PublicApplicationForm = () => {
  const [state, setState] = useState<{ client: string | number; name: string }>({ client: '', name: 'hai' });
  const [showExp, setOpenExp] = useState(false);
  const [showEdu, setOpenEdu] = useState(false);
  const [data, setData] = useState({
    experience: [{}],
  });
  const [educations, setEducations] = useState([]);
  const [experiences, setExperiences] = useState([]);
  const classes = useStyles();
  const radioValues = [{ value: 'yes', label: 'Yes' }, { value: 'no', label: 'No' }];
  const variables = { title: 'How did you hear about us?*', typeOfService: 'Type of Service*' };
  const relationOptions = ['Walk-In', 'Employee Referral', 'Job Boards', 'Job Fair', 'Social Media'];
  const checkBoxLabel = 'Please be informed that your application to this job offer will trigger some processing of your personal data by the  company. For more information on data processing, please refer to the company’s talent acquisition privacy policy.';

  const handleChange = ({ target }: ChangeEvent<{ name?: string; value: unknown }>) => {
    setState({ ...state, [target.name as keyof typeof state]: target.value });
  };

  const handleBlur = (event: any) => {
    data.experience[0] = { ...data.experience[0], [event.target.name]: event.target.value };
    setData({ ...data });
  };

  const onAddEdu = (edu: any) => { setEducations([...educations, edu]); setOpenEdu(false); };
  const onAddExp = (exp: any) => { setExperiences([...experiences, exp]); setOpenExp(false); };

  return (
    <Grid className={classes.pageContainer} container>
      <Grid className={classes.formContainer} item xs={12}>
        <Form
          onSubmit={(values) => { console.log(values); }} // eslint-disable-line no-console
          render={({ handleSubmit }) => (
            <form onSubmit={handleSubmit}>
              <Typography className={classes.formHeading} variant="h5">Personal Information</Typography>
              <Box className={classes.marginedBottom}>
                <FieldFileUploader
                  required
                  fileType="avatars"
                  accept={['image/*']}
                  name="resume"
                />
              </Box>
              <FormPersonalInfo setData={setData} data={data} />
              <Box className={classes.spaced}>
                <Box className={classes.fieldContainer}>
                  <Typography className={classes.noMarginBottom} variant="h6">Experience</Typography>
                  <IconButton color="primary" onClick={() => { setOpenExp(!showExp); }}><AddCircleIcon /></IconButton>
                </Box>
                {
                  showExp && (
                    <FormExperience
                      onCancel={() => setOpenExp(false)}
                      onSave={onAddExp}
                      handleBlur={handleBlur}
                    />
                  )
                }
                {experiences.map((exp, index) => <ItemExperience key={index} exp={exp} />)}
              </Box>
              <Box className={classes.spaced}>
                <Box className={classes.fieldContainer}>
                  <Typography className={classes.noMarginBottom} variant="h6">Education</Typography>
                  <IconButton color="primary" onClick={() => { setOpenEdu(!showEdu); }}><AddCircleIcon /></IconButton>
                </Box>
                {
                  showEdu && (
                    <FormEducation
                      onCancel={() => setOpenEdu(false)}
                      onSave={onAddEdu}
                      setData={setData}
                      data={data}
                    />
                  )
                }
                {educations.map((edu, index) => <ItemEducation key={index} edu={edu} />)}
              </Box>
              <Typography className={classes.formText} variant="h6">On the web</Typography>
              <Box className={classes.fieldContainer}>
                <FieldInput className={classes.textField} type="text" required name="applicant-linkedin" label="Linkedin" onChange={(event: React.ChangeEvent<HTMLInputElement>) => setData({ ...data, [event.target.name]: event.target.value })} />
              </Box>
              <Box className={`${classes.fieldContainer} ${classes.marginedBottom}`}>
                <FieldInput className={classes.textField} type="text" required name="applicant-facebook" label="Facebook" onChange={(event: React.ChangeEvent<HTMLInputElement>) => setData({ ...data, [event.target.name]: event.target.value })} />
              </Box>
              <Typography className={classes.formText} variant="h6">Resume</Typography>
              <Box className={`${classes.fieldContainer} ${classes.marginedBottom}`}>
                <Box className={classes.dropZone}>
                  <FieldFileUploader
                    required
                    fileType="resumes"
                    fieldLabel="Click or Drag file here to upload resume"
                    accept={['application/pdf']}
                    name="resume"
                  />
                </Box>
              </Box>
              <Typography className={classes.formText} variant="h6">Check the box of the ones you don&apos;t have.</Typography>
              <Box className={classes.marginedBottom}>
                <FormGovernmentIds setData={setData} data={data} />
              </Box>
              <Typography className={classes.formText} variant="h6">Preliminary Questions</Typography>
              <Box className={`${classes.fieldContainer} ${classes.marginedBottom}`}>
                <FormControl variant="outlined" className={classes.textField}>
                  <InputLabel htmlFor="outlined-age-native-simple">{variables.title}</InputLabel>
                  <Select
                    native
                    value={state.client}
                    onChange={handleChange}
                    label="How did you hear about us?"
                    inputProps={{ name: 'client', id: 'outlined-age-native-simple' }}
                    onClick={
                      (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => setData({
                        ...data,
                        [event.target.name]: event.target.value,
                      })
                    }
                  >
                    <option aria-label="None" value="" />
                    {relationOptions.map((item, index) => (
                      <option key={index} value={item.replace(' ', '-').toLowerCase()}>{item}</option>))}
                  </Select>
                </FormControl>
              </Box>
              <FormRadioQuestions
                fieldClassName={classes.fieldContainer}
                textClassName={classes.textField}
                values={radioValues}
                setData={setData}
                data={data}
              />
              <Box className={classes.fieldContainer}>
                <FieldCheckbox className={classes.textField} name="confirm-registration" label={checkBoxLabel} />
              </Box>
              <Box className={classes.fieldContainer}>
                <Button component="button" type="submit" className={classes.spaced} variant="contained" color="primary">
                  Submit
                </Button>
              </Box>
            </form>
          )}
        />
      </Grid>
    </Grid>
  );
};

export default PublicApplicationForm;

FormPersonalInfo 组件由申请人名字、姓氏、电子邮件、位置、手机等字段组成。

当我单击 AddCircleIcon 按钮以显示其他一些字段并添加经验/教育时,我收到此错误。

当我点击提交按钮时,我只得到了这个日志。

这是与教育表格相同的经验表格

我的目标是像这样将经验和教育数组添加到结果集中。

【问题讨论】:

    标签: reactjs typescript react-final-form


    【解决方案1】:

    错误很明显,嵌套了&lt;form&gt;标签。

    重现错误的快速示例

    const { useState, useEffect } = React;
    
    const App = () => {
    
    return <form>
      <form></form>
    </form>
    }
    
    ReactDOM.render(
        <App />,
        document.getElementById('root')
      );
    <script src="https://unpkg.com/react/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    <div id="root"></div>

    在您的情况下,showExp 在单击操作后计算为 true,然后 FormExperience 组件(其中显然包含 form 标记)呈现,validateDOMNesting 引发错误。

      showExp && (
        <FormExperience
          onCancel={() => setOpenExp(false)}
          onSave={onAddExp}
          handleBlur={handleBlur}
        />)
    

    【讨论】:

    • 是的,这会影响我为什么没有从中获取值吗?
    • 除此之外我看不到任何其他罪魁祸首,所以是的
    【解决方案2】:

    在我设法使用 Material UI Portals 解决它之前,我遇到过类似的情况

        import React from "react";
        import Portal from "@material-ui/core/Portal";
    
        export default NestedForms = () => {
    
          const container = React.useRef(null);
    
          return (
            <>
              <form>
                  {/*form content  */}
                  <div ref={container} />
                  {/*form content  */}
              </form>
    
              <Portal container={container.current}>
                  <form>
                          {/*  otherform */}
                  <form/>
              </Portal>
            </>
          )
        }
    

    【讨论】:

      猜你喜欢
      • 2019-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-10
      相关资源
      最近更新 更多