Как передать входные значения из дочернего компонента Form в состояние его родительского компонента для отправки с помощью ловушек реагирования? - PullRequest
0 голосов
/ 18 октября 2019

Я настраиваю многошаговую форму для обработки входа с помощью Next.js и Material-UI. На странице signup.js, расположенной в pages/signup.js. Моя многошаговая форма создана. На этой странице дочерние компоненты, которые должны отображаться как содержимое шага, определены в getStepContent(step), а основной компонент называется SignInSide под ним. Шаги для перемотки вперед и назад также определены на странице signup.js. Компоненты дочерней формы содержат только входные данные. Я пытаюсь передать данные, введенные во входные данные дочернего компонента, в состояние родительского компонента на странице регистрации, signup.js, чтобы я мог отправить его. И родительский, и дочерний компоненты являются функциональными компонентами, использующими перехватчики реакции для состояния.

Я уже пытался передать реквизиты от родительского к дочернему компоненту, а затем определить «значение» компонентов TextField для {props.value}, и это сработало, когда я протестировал его со значением console.log в родительском компоненте, и увидел буквы, проходящие через него, однако имени не было: прикрепленный к нему, он просто проходил как просто буквы, поэтому я попыталсядобавить [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 (
    ...
  )
 }

Родительским компонентом является SignInSide. Я использую материал-интерфейс. Пример использования формы stepper, которую я использую, можно увидеть здесь: https://material -ui.com / Getting-Start / 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>
  );
}

Ожидается: при вводе пользователем дочерний компонент сохраняет входные данные в состоянии и передает их родительскому компоненту. поэтому он может отправить данные для регистрации.

Факт: ввод успешно передан родителю, но в неправильном формате. Он передается как «[объект объекта] (здесь вводятся буквы)», и в поле ввода пользователь может видеть [объект объекта] только в том виде, как он виден в консоли. Нет ошибок.

1 Ответ

0 голосов
/ 19 октября 2019

Ваша проблема здесь:

const handleChange = name => event => {
  props.onChange({
    [name]: event.target.value
  });
};

Вы даете своей функции props.onChange объект, но эта функция обновляет ловушку состояния, которая инициализируется строковым значением. Затем вы устанавливаете текстовое значение для объекта, когда раньше это была строка, дающая текст вашего нечетного объекта.

Кроме того, вы устанавливаете все значения формы в одну и ту же строку из родительского состояния.

Для решения этой проблемы сделайте ваше состояние объектом вместо строки.

В родительском:

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

....

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

....

return <CredentialsForm values={values} onChange={handleChange} />;

В дочернем:

<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'
/>

Рекомендуетсяно не обязательно: я бы избавился от функции handleChange в компоненте формы, так как он не добавляет ценности. Затем вызовите props.onChange непосредственно со входа и измените ваш родительский handleChange на:

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