jquense / react-formal

Sophisticated HTML form management for React
http://jquense.github.io/react-formal
MIT License
527 stars 52 forks source link

What is the right way of adding new fields dynamically? #111

Closed tsabolov closed 7 years ago

tsabolov commented 7 years ago

I have implemented a component whose render method renders react-formal's Form. The basic structure is as follows:

import React from 'react';
import Form from 'react-formal';
import yup from 'yup';

class MyComponent extends React.Component {
  constructor(...args) {
    super(...args);
    this.handleAddNewChoice = this.handleAddNewChoice.bind(this);
  }

  schema = yup.object({
    choices: yup.array().of(
      yup.object({ label: yup.string() })
    ),
  })

  handleAddNewChoice() {
    // Here I am calling Redux action which adds a new choice to the `data.choices` array
  }

  render() {
    return (
      <Form schema={this.schema} defaultValue={this.props.data}>
        {this.props.data.choices.map((choices, i) =>
          <Form.Field type="text" name={`choices[${i}].label`} />
        )}
        <button onClick={this.handleAddNewChoice}>Add new choice</button>
      </Form>
    );
  }
}

Then I call the component with data (actually the data comes from a Redux store), like this:

<MyComponent data={{ choices: [{ label: 'Choice 1' }, { label: 'Choice 2' }] }} />

The problem is that when I am adding a new item to choices array (via Redux action/reducer) and the data prop of MyComponent changes, the Form does not get the updated value. It just sticks with the previous one.

What is the right way of implementing of such a logic with react-formal?

jquense commented 7 years ago

you want to "control" the form value directly in that case. Instead of using defaultValue use value and onChange, store the current form value in state, and then you can update that value from outside the Form

tsabolov commented 7 years ago

Oh, I see. Thank you for super fast response!