React 中表单的方法论

You, web development
Back

动机

最近一年都在做 B 端的项目,由于存在着大量的表单。所以会很容易会发现在实现表单功能上,实现的方法根据不同的人会有很大的不同。

核心法则

单一数据源

首先要明确一点,要存在一个单一数据源 store, store中的状态与组件的视图是一一对应的,这样保证了数据的流动是单向的,代码在更易读的同时也更便于之后的维护,如下图所示。

Good Example

confused-tree-graph

而我们没有单一数据源的话,只是将状态交由给我们的表单组件维护,很容易出现父与子,兄与弟,孙与爷之间的数据传输,造成代码的腐败,甚至在一段时间之后自己都难以理清其中的逻辑。如下图所示。

Bad Example

ordered-tree-graph

受控组件

即自身内不存在状态(例 useState, useContext, useReducer 等等...)的组件

我们应该将所有的表单组件设计为受控组件,表单只需要关心组件状态的输入(value)及输出(onChange),这样一来我们不仅可以通过其他组件更新组件的状态,也可以很容易地将状态分享到其他的 UI 组件当中

// good
function Input({ value, onChange }) {
  return (
    <input
      value={value}
      onChange={function handleChange(ev) {
        onChange(ev.target.value)
      }}
    />
  )
}

// bad
function Input({ value, onChange }) {
  const [state, setState] = useState(value)
  return (
    <input
      value={state}
      onChange={function handleChange(ev) {
        const v = ev.target.value
        setState(v)
        onChange(v)
      }}
    />
  )
}

codesanbox 例子

用户体验

初始化完成后渲染表单
在业务中我们经常会碰到这样的场景,例如有一个修改当前用户信息的表单,我们需要先通过 http 请求来向服务器获取当前用户的信息来作为表单的默认值。往往我们都是先渲染表单,等到数据加载完成之后,再次将表单重新渲染。很可能用户还在填写表单时,啪,你把表单重新渲染了,但是之前用户填写就丢失了。这就造成了用户的体验感变得很糟糕 😣
所以应当在表单初始化完成后渲染表单。

codesanbox 例子

© liaoliao666.