yaofly2012 / note

Personal blog
https://github.com/yaofly2012/note/issues
44 stars 5 forks source link

Formik #83

Open yaofly2012 opened 4 years ago

yaofly2012 commented 4 years ago

表单痛点

  1. 值的获取,同步(React Form很繁琐);
  2. 验证;
  3. 提交过程处理

Formik

image

keeping track of values/errors/visited fields, orchestrating validation, and handling submission

核心就是状态收集,除了values之外还有其他的相关状态:

  1. initialValues initialValues是必须的,用于初始化values
  2. values
  3. errors
  4. touches

并且它们都是同构的

initialValues的必要性?

子组件如何访问Formik组件的状态和方法?

这就涉及如何使用Formik了。

  1. Render props方式;
  2. Hooks

form方法:

  1. handleChange
  2. handleBlur

注意:handleChangehandleBlur的实参必须是SyntheticEvent。但有些UI库中InputonChange事件处理函数只是value值,如果遇到这种情况可以利用Formik的方法显示的更新值。

Formik只做逻辑,不做UI。

把逻辑和UI分开是很明智的,更容易扩展。 Formik只做逻辑部分。

yaofly2012 commented 4 years ago

Validation

一、Validation

Formik的validation分为两个部分:

  1. 校验:validation
  2. 错误信息:errorMessage

特性

  1. 同步,异步
  2. Form-level(Top Level), Field-level
  3. schema-based

触发时机

  1. Run after any onChange and onBlur by default;
  2. Run at the beginning of a submission attempt;
  3. Manually Triggering Validation:
    • validateField
    • validateForm

Issues

1. validateForm的含义容易让人误解。

它是验证表单所有字段,但是验收失败并不会reject Promise(下面的代码 是错误的用法)。

// 是错误的用法
form.validateForm().then(() => {
    console.log(‘验证成功’)
}, () => {
    console.log(‘验证失败’)
})

// 正确的用法
form.validateForm().then(() => {
    console.log(‘验证完成’)
},)

它本质就是单纯的构建最新的errors对象,并且validateForm不会修改touches对象(即此时及时字段有错误,错误信息也可能不会展示的)。

二、数组和嵌套对象

  1. 表单组件的name属性只能是字符串,所以采用lodash-like dot(bracket ) paths命名name的方式 这就涉及嵌套对象属性和name的映射关系。
  2. 不管是数组还是内嵌对象属性,initailValues,values,touches,errors这四个对象都必须是同构的。

浏览器内置的表单校验

  1. If we are okay with using the browser's built-in HTML input validation, you could add a required prop to each of our inputs, specify minimum/maximum lengths (maxlength and minlength), and/or add a pattern prop for regex validation for each of these inputs.

  2. 浏览器内置表单表单校验的存在的意义? ?

Schema Validation

Yup

yaofly2012 commented 4 years ago

表单提交

提交过程

  1. pre-submit
  2. validation
  3. submission

image

注意:

  1. 只有调用handleSubmit(一般用于绑定form标签上)或者submitForm(一般用于命令式调用)才会进入【提交过程】。
  2. 触发提交和进入提交过程是异步的。

Issues:

  1. initialValues的必要性?
  2. 嵌套对象或者动态增加的属性如果改成touched? 看看这个I think solutions could be as follow

提交相关属性

  1. isValidating
  2. isSubmitting
  3. submitCount

Field

ascomponent属性区分?

yaofly2012 commented 4 years ago

Formik.tsx

formikReducer

useFormik

state(Form State)

由Filed的meta数据(getFieldMeta)和Form的数据构成:

const [state, dispatch] = React.useReducer<
    React.Reducer<FormikState<Values>, FormikMessage<Values>>
  >(formikReducer, {
    values: props.initialValues,
    errors: props.initialErrors || emptyErrors,
    touched: props.initialTouched || emptyTouched,
    status: props.initialStatus,
    isSubmitting: false,
    isValidating: false,
    submitCount: 0,
});

成员属性

const initialValues = React.useRef(props.initialValues);
const initialErrors = React.useRef(props.initialErrors || emptyErrors);
const initialTouched = React.useRef(props.initialTouched || emptyTouched);
const initialStatus = React.useRef(props.initialStatus);
const isMounted = React.useRef<boolean>(false);
const fieldRegistry = React.useRef<FieldRegistry>({});

enableReinitializeinitialValues, initialErrors, initialTouched, initialStatus关系: 在4个useEffect里更新初始值。

方法

  1. 统一的事件处理函数

    • handleChange
    • handleBlur
    • handleSubmit
    • handleReset
  2. Helper方法

依赖

  1. react-fast-compare 深度比较

  2. useFormik

    const handleChange = React.useCallback(
    (
      eventOrPath: string | React.ChangeEvent<any>
    )

    参数是字符串的应用场景?

  3. setIn/getIn: 通过路径方式set/get对象值

  4. Formit组件 为啥需要FormikProvider作为父组件?渲染子元素时并不涉及FormikProvider

ts:

  1. 函数模板
  2. 类型限制关系&
  3. Values extends FormikValues = FormikValues

  4. type reactjs:
  5. React.useEffect 居然可以穿第二个参数
  6. React.useRef
  7. React.useCallback

Issues:

  1. useEventCallback的用处?
yaofly2012 commented 3 years ago

FieldArray

为啥要实现FieldArray?