final-form / react-final-form

🏁 High performance subscription-based form state management for React
https://final-form.org/react
MIT License
7.38k stars 480 forks source link

[Question] How set initialErrors on form render first time? #339

Open borm opened 6 years ago

borm commented 6 years ago

Subj

borm commented 6 years ago

https://codesandbox.io/s/nr3n93691l

It`s correct way?

maciejmyslinski commented 6 years ago

The way you proposed is complicated, but works. The thing is, final form calculates errors for you whether the value comes from default values or not. What matters is how you display this error. Consider this example: https://codesandbox.io/s/v040xl2m15

borm commented 5 years ago

@maciejmyslinski No, i have created my own field component, for better understand i will show example

import Input from 'some/ui/framework';

class MyOwnField extend React.Component {
  render() {
    const {
      input,
      meta: {
        error,
        submitError,
        touched,
        dirtySinceLastSubmit,
        data: { initialError },
      },
    } = this.props;

    const hasError = (error && touched) || (submitError && !dirtySinceLastSubmit);
    const errorMessage = error || submitError;

    return (
      <div>
        <Input {...input} />
        {initialError && initialError}
        {hasError && errorMessage}
      </div>
    );
  }
}

it`s why i need initial error instead of default final-form error


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

...
<Field name="test" component={MyOwnField} />
...
maciejmyslinski commented 5 years ago

@borm don't overcomplicate 🙂

You need no custom initialError. I took your custom field component and created a simple example with an error being rendered initially.

https://codesandbox.io/s/qlpw1394xq

yourcelf commented 5 years ago

Just to add a little more detail, as I spent a while on this question too, and found it a little under-documented: there isn't a way to pipe an initial error through react-final-form's machinery; but there isn't a need to. There are 3 types of error that you might want to render:

For each of these, it's up to you to figure out exactly when you want these errors to show up, probably using one of meta.touched, meta.pristine, meta.dirtySinceLastSubmit. For my code, I ended up with logic like this:

const getError = (meta, initialError) => {
    return (
        (meta.touched && meta.error) ||
        (!meta.dirtySinceLastSubmit && (meta.submitError || initialError))
    )
}

I use it in a field like this (assuming props.initialError is in scope from the calling context):

<Field name="firstName" validate={value => !value ? "This is required." : undefined}>
  {({input, meta}) => (
    <div className="form-group">
      <input {...input} type="text" className="form-control" />
      <div className="error-msg">{getError(meta, props.initialError.firstName)}</div>
    </div>
  )}
</Field>

I suppose react-final-form could offer a way to set initialErrors and take care of the accounting for those (and perhaps adding a meta.initialError property next to meta.submitError and meta.error), but that would add a bunch of code to the library for a fairly trivial gain. Since you already need to concern yourself with exactly when to show an error based on touched-ness, pristine-ness, etc., and these requirements differ between local/submit/initial errors (and requirements will differ for different apps/forms), you'll already need some kind of custom logic surrounding error display. Adding an initial error message from outside the form into that mix isn't too burdensome.