Skip to content

Files

Latest commit

 

History

History
137 lines (103 loc) · 4.61 KB

faq.md

File metadata and controls

137 lines (103 loc) · 4.61 KB

FAQ

Why not Redux-Form or Formik?

Those are both excellent form libraries. Like all engineering decisions, it depends on your requirements and what trade-offs you wish to make. Here is a Comparison Table.

Why no HOC?

The only benefit that higher order components provide over render props is access to the injected props from within component lifecycle methods. Plus, it only takes a single line of code to transform a component with a render (or component) prop into a HOC. If you really want a HOC, you can write your own:

import { Form, Field } from 'react-final-form'

class MyForm extends React.Component {
  componentDidMount() {
    const { initialize } = this.props // access to injected props
    ajax.fetch('/myData').then(data => initialize(data))
  }

  render() {
    return <form onSubmit={this.props.handleSubmit}>...some fields...</form>
  }
}

// 👇 THIS LINE IS THE HOC 👇
export default props => <Form {...props} component={MyForm} />

Doing a HOC properly, as a library should, with hoisted statics and displayName and ref, etc., is a hassle and would add unnecessary bulk.

How can I trigger a submit from outside my form?

This is a common question I see from people migrating from redux-form. There are three possible solutions:

Via document.getElementById()

You can use the DOM to get a reference to your <form> element and dispatch a submit event on it. Note that you cannot just call submit(), as this will not trigger React's event handlers.

<button onClick={() => {
  document.getElementById('myForm').submit() // ❌
}}>Submit</button>

<button onClick={() => {
  document.getElementById('myForm').dispatchEvent(new Event('submit')) // ✅
}}>Submit</button>

<form id="myForm" onSubmit={handleSubmit}>
  ...fields go here...
</form>

See Sandbox Example.

Via Closure

If you define a variable outside of your form, you can then set the value of that variable to the handleSubmit function that 🏁 React Final Form gives you, and then you can call that function from outside of the form.

let submit
return (
  <div>
    <button onClick={submit}>Submit</button> // ❌ Not overwritten closure value
    <button onClick={event => submit(event)}>Submit</button> // ✅
    <Form
      onSubmit={onSubmit}
      render={({ handleSubmit }) => {
        submit = handleSubmit
        return <form>...fields go here...</form>
      }}
    />
  </div>
)

See Sandbox Example.

Via Redux Dead Drop

If you're already using Redux, you could potentially use the same mechanism that redux-form uses: Redux Dead Drop.

Why can't I have numeric keys in an object?

So you want to have value structured like { 13: 'Bad Luck', 42: 'Meaning of Everything' }, but you're getting an error. This is because the setIn engine in 🏁 Final Form uses the isNaN-ness of keys to determine whether or not it should create an object or an array when constructing deep data structures. Adding checks for bracket[3] syntax as opposed to dot.3 syntax adds a lot of complexity, and has consciously been avoided.

You will need to convert all your keys to NaN strings before initializing your form values, and then convert them back to numbers on submit. It's not that hard.

const stringifyKeys = values =>
  Object.keys(values).reduce((result, key) => {
    result[`key${key}`] = values[key]
    return result
  }, {})

const destringifyKeys = values =>
  Object.keys(values).reduce((result, key) => {
    result[Number(key.substring(3))] = values[key]
    return result
  }, {})

<Form
  onSubmit={values => onSubmit(destringifyKeys(values))}
  initialValues={stringifyKeys(initialValues)}>
  ...
</Form>