jannikbuschke / formik-antd

Simple declarative bindings for Ant Design and Formik.
https://codesandbox.io/s/github/jannikbuschke/formik-antd-example
MIT License
591 stars 81 forks source link

Run a function over errors in Form.Item / validationSchema? (Yup, i18next) #144

Open yoruvo opened 4 years ago

yoruvo commented 4 years ago

Hi,

my setup for forms is:

This setup works quite well for labels, placeholders etc. but I'm struggling with errors.

If I design my validation schema for Formik like so:

import * as Yup from "yup"
import { useTranslation } from "react-i18next"

const { t } = useTranslation()

  const validationSchema = Yup.object().shape({
    name: Yup.string().required(t("form.validation.required")),
  })

then the validation is translated correctly, but the translation does not change when switching languages in i18next.

A solution suggested in many other issues I've read about the topic (from the different projects) is to use the i18next t() function in the React output instead. However, for me, this is being handled by formik-antd's Form.Item class.

However, I cannot see any option to pass that t() function to the Form.Item error output without overriding the Form.Item.

Could you advise on how to proceed?

jannikbuschke commented 4 years ago

You might be able to place the schema and the calls to the t function inside a component. To not reintantiate the schema on every render you probabaly want to wrap it in a React.useMemo call. The memo need to be re-evaluated on every language change. I guess the react-i18next exposes somewhere the current language value in a hook. This value you would need to pass to the memo as a dependency.

So something along these lines:

function MyComponent() {
  const { t, lang } = useTranslation(); // not sure how to get lang, it might be somewhere else
  const schema = React.useMemo(()=> {
     return /* Yup.object().shape.... with t() calls*/, 
       , [lang]); // <-- dependency for useMemo, so that on every change of `lang` the schema gets re-created
  return <Formik ....
}
ryall commented 4 years ago

I agree this would be useful and the solution suggested isn't possible in my case because my validation schema does not return translated messages but rather a serialized object to generate the translated message. I do this because my API needs to be language agnostic, and some form errors are generated there.

I was solving this before using Antd with a custom ErrorMessage component, but with Antd, the error is internal to the FormItem.