tutorial 教程

通过构建 formik,来学习 它

我在 React Alicante 的演讲确实是开始的最好方式。它介绍了库(通过观看我构建它的迷你版本),并演示了如何使用现实的东西构建一个非凡的表单(使用数组、自定义输入等)。大约 45 分钟长。

基础

如果您只想跳到一些代码中,这里有一个基本的快速演练…

假设您想要构建一个允许您编辑用户数据的表单。但是,您的用户 API 有类似这样的嵌套对象。

  1. {
  2. id: string,
  3. email: string,
  4. social: {
  5. facebook: string,
  6. twitter: string,
  7. // ...
  8. }
  9. }
  1. // EditUserDialog.js
  2. import React from 'react';
  3. import Dialog from 'MyImaginaryDialogComponent'; // 这不是真的包, 假设它存在就好了
  4. import {Formik} from 'formik';
  5. const EditUserDialog = ({user, updateUser, onClose}) => {
  6. return (
  7. <Dialog onClose={onClose}>
  8. <h1>Edit User</h1>
  9. <Formik
  10. initialValues={user /** { email, social } */}
  11. onSubmit={(values, actions) => {
  12. MyImaginaryRestApiCall(user.id, values).then(
  13. updatedUser => {
  14. actions.setSubmitting(false);
  15. updateUser(updatedUser);
  16. onClose();
  17. },
  18. error => {
  19. actions.setSubmitting(false);
  20. actions.setErrors(transformMyRestApiErrorsToAnObject(error));
  21. actions.setStatus({msg: 'Set some arbitrary status or data'});
  22. }
  23. );
  24. }}
  25. render={({
  26. values,
  27. errors,
  28. status,
  29. touched,
  30. handleBlur,
  31. handleChange,
  32. handleSubmit,
  33. isSubmitting
  34. }) => (
  35. <form onSubmit={handleSubmit}>
  36. <input
  37. type="email"
  38. name="email"
  39. onChange={handleChange}
  40. onBlur={handleBlur}
  41. value={values.email}
  42. />
  43. {errors.email && touched.email && <div>{errors.email}</div>}
  44. <input
  45. type="text"
  46. name="social.facebook"
  47. onChange={handleChange}
  48. onBlur={handleBlur}
  49. value={values.social.facebook}
  50. />
  51. {errors.social && errors.social.facebook && touched.facebook && (
  52. <div>{errors.social.facebook}</div>
  53. )}
  54. <input
  55. type="text"
  56. name="social.twitter"
  57. onChange={handleChange}
  58. onBlur={handleBlur}
  59. value={values.social.twitter}
  60. />
  61. {errors.social && errors.social.twitter && touched.twitter && (
  62. <div>{errors.social.twitter}</div>
  63. )}
  64. {status && status.msg && <div>{status.msg}</div>}
  65. <button type="submit" disabled={isSubmitting}>
  66. Submit
  67. </button>
  68. </form>
  69. )}
  70. />
  71. </Dialog>
  72. );
  73. };

为了书写表单不那么冗长。Formik 有几个助手来帮你保存按键。

  • <Field>
  • <Form />

以下内容与之前的表单完全相同,但使用了<Form /><Field />,:

  1. // EditUserDialog.js
  2. import React from 'react';
  3. import Dialog from 'MySuperDialog';
  4. import {Formik, Field, Form} from 'formik';
  5. const EditUserDialog = ({user, updateUser, onClose}) => {
  6. return (
  7. <Dialog onClose={onClose}>
  8. <h1>Edit User</h1>
  9. <Formik
  10. initialValues={user /** { email, social } */}
  11. onSubmit={(values, actions) => {
  12. MyImaginaryRestApiCall(user.id, values).then(
  13. updatedUser => {
  14. actions.setSubmitting(false);
  15. updateUser(updatedUser);
  16. onClose();
  17. },
  18. error => {
  19. actions.setSubmitting(false);
  20. actions.setErrors(transformMyRestApiErrorsToAnObject(error));
  21. actions.setStatus({msg: 'Set some arbitrary status or data'});
  22. }
  23. );
  24. }}
  25. render={({errors, status, touched, isSubmitting}) => (
  26. <Form>
  27. <Field type="email" name="email" />
  28. {errors.email && touched.email && <div>{errors.email}</div>}
  29. <Field type="text" name="social.facebook" />
  30. {errors.social.facebook && touched.social.facebook && (
  31. <div>{errors.social.facebook}</div>
  32. )}
  33. <Field type="text" name="social.twitter" />
  34. {errors.social.twitter && touched.social.twitter && (
  35. <div>{errors.social.twitter}</div>
  36. )}
  37. {status && status.msg && <div>{status.msg}</div>}
  38. <button type="submit" disabled={isSubmitting}>
  39. Submit
  40. </button>
  41. </Form>
  42. )}
  43. />
  44. </Dialog>
  45. );
  46. };

这更好,但所有这些errorstouched逻辑仍然是相当重复的。formik 有一个组件<ErrorMessage>,可以简化更多的事情。它接受渲染 props 或组件 props 以获得最大的灵活性。

  1. // EditUserDialog.js
  2. import React from 'react';
  3. import Dialog from 'MySuperDialog';
  4. import {Formik, Field, Form, ErrorMessage} from 'formik';
  5. const EditUserDialog = ({user, updateUser, onClose}) => {
  6. return (
  7. <Dialog onClose={onClose}>
  8. <h1>Edit User</h1>
  9. <Formik
  10. initialValues={user /** { email, social } */}
  11. onSubmit={(values, actions) => {
  12. MyImaginaryRestApiCall(user.id, values).then(
  13. updatedUser => {
  14. actions.setSubmitting(false);
  15. updateUser(updatedUser);
  16. onClose();
  17. },
  18. error => {
  19. actions.setSubmitting(false);
  20. actions.setErrors(transformMyRestApiErrorsToAnObject(error));
  21. actions.setStatus({msg: 'Set some arbitrary status or data'});
  22. }
  23. );
  24. }}
  25. render={({errors, status, touched, isSubmitting}) => (
  26. <Form>
  27. <Field type="email" name="email" />
  28. <ErrorMessage name="email" component="div" />
  29. <Field type="text" className="error" name="social.facebook" />
  30. <ErrorMessage name="social.facebook">
  31. {errorMessage => <div className="error">{errorMessage}</div>}
  32. </ErrorMessage>
  33. <Field type="text" name="social.twitter" />
  34. <ErrorMessage
  35. name="social.twitter"
  36. className="error"
  37. component="div"
  38. />
  39. {status && status.msg && <div>{status.msg}</div>}
  40. <button type="submit" disabled={isSubmitting}>
  41. Submit
  42. </button>
  43. </Form>
  44. )}
  45. />
  46. </Dialog>
  47. );
  48. };