如何将输入值从子 Form 组件传递到其父组件的状态以使用 React hooks 提交?

Dar*_*rge 2 reactjs material-ui next.js react-hooks

我正在设置一个多步骤表单来处理使用 Next.js 和 Material-UI 的登录。在signup.js位于 的页面中pages/signup.js。我的多步骤表单已创建。在该页面中,定义了作为步骤内容显示的子组件getStepContent(step),并在其下面调用主组件SignInSide。页面上还定义了前进和后退的步骤signup.js。子表单组件仅包含输入。我试图将输入到子组件表单输入中的数据传递到注册页面中父组件的状态,signup.js以便我可以提交它。父组件和子组件都是使用 React hooks 进行状态的功能组件。

我已经尝试将 props 从父组件传递到子组件,然后将 TextField 组件的“值”定义为 {props.value},当我使用父组件中的 console.log 值对其进行测试时,该方法有效我看到了字母,但是没有 name: 附加到它,它只是作为字母出现,所以我尝试添加 [name]: event.target.value 但当我尝试在输入中写入文本时字段它只是说 [Object object] 但是,在控制台中我可以看到 [Object object](在此处插入键入的字母),因此它记录了文本,但不正确,并且键入的文本在输入框中不可见。

这就是步骤内容所在的位置。

const steps = ['Welcome', 'Information', 'Creative', 'Confirm'];

function getStepContent(step) {
  const [value, setValue] = React.useState('');

  //set state for returned input values
  function handleChange(newValue) {
    setValue(newValue);
  }

  switch (step) {
    case 0:
      return (
        <div style={{ padding: '8em 0 4em' }}>
          <Hero title='Welcome' paragraph="Let's get you signed up." />
        </div>
      );
    case 1:  // Form Components
      return <CredentialsForm value={value} onChange={handleChange} />;
    case 2:
      return <CreativeForm />;
    case 3:
      return <Review />;
    default:
      throw new Error('Unknown step');
  }
}

// Sign In Page
export default function SignInSide() {
  const classes = useStyles();
  const [activeStep, setActiveStep] = React.useState(0);
  const [form, setForm] = React.useState(false);
  // Forward and Back button functions, the buttons are defined here, in the parent page component.
  const handleNext = () => {
    setActiveStep(activeStep + 1);
  };

  const handleBack = () => {
    setActiveStep(activeStep - 1);
  };

  const handleFormExtend = () => {
    setForm(true);
    setActiveStep(activeStep + 1);
  };

  return (
    ...
  )
 }

Run Code Online (Sandbox Code Playgroud)

父组件是SignInSide. 我使用的是material-ui。我使用的步进器形式的示例可以在这里看到: https: //material-ui.com/getting-started/templates/checkout/其类似的代码,我只是将文本字段更改为轮廓并设置道具的逻辑从父母那里传过来的。

内部<CredentialsForm value={value} onChange={handleChange} />组件。

export default function CredentialsForm(props) {
  const classes = useStyles();
  // Floating Form Label
  const inputLabel = React.useRef(null);
  const [labelWidth, setLabelWidth] = React.useState(0);
  React.useEffect(() => {
    setLabelWidth(inputLabel.current.offsetWidth);
  }, []);

  //Send input value to parent state
  const handleChange = name => event => {
    props.onChange({
      [name]: event.target.value
    });
  };

  return (
    <div className={classes.paper}>
      <Avatar className={classes.avatar}>
        <LockOutlinedIcon />
      </Avatar>
      <Typography component='h1' variant='h5'>
        Who Are U?
      </Typography>
      <form className={classes.form} noValidate>
        <Grid container spacing={2}>
          <Grid item xs={2} md={2}>
            <FormControl
              margin='normal'
              variant='outlined'
              fullWidth
              required
              className={classes.formControl}
            >
              <InputLabel
                ref={inputLabel}
                htmlFor='outlined-userTitle-native-simple'
              >
                Title
              </InputLabel>
              <Select
                native
                value={props.value}
                onChange={handleChange('title')}
                labelWidth={labelWidth}
                required
                inputProps={{
                  name: 'title'
                }}
              >
                <option value='' />
                <option value={10}>Mr.</option>
                <option value={20}>Ms.</option>
                <option value={20}>Mrs.</option>
                <option value={30}>Non-Binary</option>
              </Select>
            </FormControl>
          </Grid>
          <Grid item xs={5} md={5}>
            <TextField
              variant='outlined'
              margin='normal'
              required
              fullWidth
              value={props.value}
              onChange={handleChange('firstName')}
              id='first'
              label='First Name'
              name='firstname'
            />
          </Grid>
        </Grid>
      </form>
    </div>
  );
}

Run Code Online (Sandbox Code Playgroud)

预期:在用户输入时,子组件将输入保存在状态中并将其传递给父组件,以便它可以提交数据进行注册。

实际:输入已成功传递给父级,但格式错误。它作为“[Object object](用户在此处键入字母)”传递,并且在输入字段中用户只能看到控制台中看到的[Object object]。没有错误。

Bri*_*son 5

你的问题在这里:

const handleChange = name => event => {
  props.onChange({
    [name]: event.target.value
  });
};
Run Code Online (Sandbox Code Playgroud)

您为props.onChange函数提供了一个对象,但该函数正在更新使用字符串值初始化的状态挂钩。然后,您将文本值设置为一个对象,而它曾经是一个字符串,给出了看起来很奇怪的对象文本。

此外,您还将所有表单值设置为父状态中的同一字符串。

要解决此问题,请将状态设置为对象而不是字符串。

在父级中:

const [values, setValues] = React.useState({title: '', firstName: ''});

....

function handleChange(newValue) {
  setValues({...values, ...newValue});
}

....

return <CredentialsForm values={values} onChange={handleChange} />;
Run Code Online (Sandbox Code Playgroud)

儿童时期:

<Select
  native
  value={props.values.title} // Change to this
  onChange={handleChange('title')}
  labelWidth={labelWidth}
  required
  inputProps={{
    name: 'title'
  }}
>

....

<TextField
  variant='outlined'
  margin='normal'
  required
  fullWidth
  value={props.values.firstName} // Change to this
  onChange={handleChange('firstName')}
  id='first'
  label='First Name'
  name='firstname'
/>
Run Code Online (Sandbox Code Playgroud)

推荐但不是必需的:我会删除handleChange表单组件中的功能,因为它并没有真正增加价值。然后props.onChange直接从输入调用,并将您的父级更改handleChange为:

const handleChange = name => event => {
  setValues({...values, [name]: event.target.value});
}
Run Code Online (Sandbox Code Playgroud)