bietkul / react-reactive-form

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

How to render form on state/prop change - strict = false #44

Closed cyberwombat closed 5 years ago

cyberwombat commented 5 years ago

Describe the bug I am trying to pass some props/state to the form. I call useEffect' to set the info but the form does not re-render. I have setstrict` to false in both FieldGroup and FieldControl - I am not sure what I am missing.

I have made a sandbox here

In the sample code below which is what is in sandbox I am calling useEffect to set a variable that I want passed as the value of one of my form inputs. The default value is 'foo' and I want the form to show the updated state 'bar'. How can I achieve this?

Sample Code

import React, { useState, useEffect } from 'react'

import {
  FieldControl,
  FieldGroup,
  FormControl,
  FormGroup
} from 'react-reactive-form'

const TextInput = ({
  meta,
  handler
}) => (
<>
  <labeL>{meta.placeholder}</labeL>
  <input {...handler()} />
  </>
)

const MyForm = (props) => {
  useEffect(() => {
    setStickerStyle('bar')
  }, [])

  const [stickerStyle, setStickerStyle] = useState('foo')

  const myForm = new FormGroup({
    style: new FormControl(stickerStyle)
  })

  const handleSubmit = (e) => {
    e.preventDefault()
  }

  return (
    <>
       <form onSubmit={() => handleSubmit}>
         <h1>{stickerStyle}</h1>
         <FieldGroup
           strict={false}
           control={myForm}
           render={({ invalid, pristine, pending, value }) => (
             <div>
               <FieldControl
                 strict={false}
                 name="style"
                 render={TextInput}
                 meta={{ placeholder: 'This should be "bar" and not "foo"' }}

               />
               <pre>{JSON.stringify(value, 0, 2)}</pre>
             </div>
           )}
         />
       </form>

    </>
  )
}

export default MyForm

Version: 1.0.30"

cyberwombat commented 5 years ago

Ok I was able to get it to work by calling `setValue('bar') on the field: Still not clear why form doesn't update w strict off so I'll leave this open for now.

  useEffect(() => {
    ss.setValue('bar')
  }, [])

  const ss = new FormControl(stickerStyle)
  const myForm = new FormGroup({
    style: ss
  })
bietkul commented 5 years ago

I guess you want to update the control value, so let me clear you that a control's value can only be updated in the following ways:

  1. Initial state
  2. Use setValue
  3. Use patchValue
  4. Use resetValue

And, I'm not sure why you need to manage the control 's state externally.

cyberwombat commented 5 years ago

Thank you for your response. My setting the control from a prop is actually a workaround for my initial problem that perhaps you can answer. I am wanting to auto submit the form on a valid state and I need to send some props data with it. I have a listener in a functional component:

 myForm.statusChanges.subscribe((status) => {
    if (status === 'VALID') {
      debouncedSubmit( { ...myForm.value, custom: someProp })
    }
  })

However the current props are not available in the listener either. I then tried to pass the props as a form meta value and access them in the listener as myForm.meta with same result - always just the initial props. How can I access latest props in the listener?

bietkul commented 5 years ago

Just update the meta property to the latest props whenever your prop changes, for example, you can set meta property in componentDidUpdate or by using useEffect.

cyberwombat commented 5 years ago

Ok yes that works. I was thrown off expecting the form to rerender on new props. Thank you.