bietkul / react-reactive-form

Angular like reactive forms in React.
MIT License
309 stars 32 forks source link

Not updating with react hooks #55

Closed sayax closed 5 years ago

sayax commented 5 years ago

Describe the bug A clear and concise description of what the bug is. Field Group state not updating with react useState hook

To Reproduce Steps to reproduce the behavior: 1) Create reactive form 2) create const [loading, setLoading] = useState(false) 3) create button <Button disabled={!form.valid || loading} className="primary" onClick={submit} /> 4) change state on click const submit = () => { setLoading(true); }

Expected behavior A clear and concise description of what you expected to happen. button disabled has loading = true state Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Additional context Add any other context about the problem here.

sayax commented 5 years ago

1.5) create form template

    <FieldGroup
      control={form}
      render={({ get, invalid }) => (
          <>
          <FieldControl
            name="username"
            render={({ handler, touched, hasError, meta }) => (
            <StyledFormField
              error={
                (touched && hasError('required') && 'required')
              }
            >
              <Input
                as={MaskedInput}
                mask={['+', '7', ' ', /\d/, /\d/, /\d/, ' ', /\d/, /\d/, /\d/, ' ', /\d/, /\d/, ' ', /\d/, /\d/]}
                placeholder=""
                {...handler()}
              />
            </StyledFormField>
            )}
          />
          <Button disabled={!form.valid || loading} className="primary" onClick={submit} />
          </>
      )}
    />
bietkul commented 5 years ago

By default, Field components only get re-render only when there is a change in the control's state. It's recommended to not use the state under the Field component for better performance. I can see that you're using a state variable named loading, it's better to put the Button component outside of the form, for example:

import { Field, ... } from 'react-reactive-form';
...
<>
  <FieldGroup
      control={form}
      render={({ get, invalid }) => (
          <>
          <FieldControl
            name="username"
            render={({ handler, touched, hasError, meta }) => (
            <StyledFormField
              error={
                (touched && hasError('required') && 'required')
              }
            >
              <Input
                as={MaskedInput}
                mask={['+', '7', ' ', /\d/, /\d/, /\d/, ' ', /\d/, /\d/, /\d/, ' ', /\d/, /\d/, ' ', /\d/, /\d/]}
                placeholder=""
                {...handler()}
              />
            </StyledFormField>
            )}
          />
          </>
      )}
    />
  <Field
    strict={false}
    control={form}
    render={({ invalid }) => <Button disabled={invalid || loading} className="primary" onClick={submit} />}
  />  
</>

If you still want to bypass it, please use strict prop as false in FieldGroup and FieldControl to avoid this default behavior, check here.