Web开发编程网
分享Web开发相关技术

Hooked-Form v4

这是我最后一篇文章的后续报道

在提出第4版Hooked-Form时,我提醒自己我对Hooked-Form的目标是什么:

  • 捆束尺寸小
  • 开箱即用的高性能
  • 良好的开发人员经验

在版本3中,这些是通过一种或另一种方式实现的,但是我知道这会更好,因此我退后一步,研究了可能的方式。

在第一部分中,我将讨论一个较小的示例中Hooked-Form的工作方式,在以下部分中,我将讨论如何尝试改进该库的目标。

它是如何工作的

我们不必重新发明轮子,在redux-form中使用的Form-Field方法是非常好的方法,并且可以很好地扩展。该方法的基本原理一直保留下来,但始终以尽可能减小束的大小为思路。

让我们用Hooked-Form做一个最小的例子。假设我们有一个组件,您可以在其中编辑您的姓名和朋友。我们的表单将具有一组初始值,我们可以提交它。

const Wrapper = ({ children, name, friends }) => {
  const initialValues = React.useMemo(() => ({
    name: props.name,
    friends: props.friends,
  }, [name, friends]);

  return (
    <HookedForm onSubmit={console.log} initialValues={initialValues}>
      {children}
    </HookedForm>
  )
}

这就是您所需要的,所有选项都可以在这里找到。在<HookedForm>将一个form标签为您在引擎盖下,绑定就可以了的onsubmit。您可能会想,但是如果我想传递额外的属性怎么办?好吧,任何传递的不是选项的属性HookedForm都将绑定到form标签,这使您可以提供例如className

让我们做一个,TextField以便我们可以在表单中更改我们的名称。

const TextField = ({ fieldId }) => {
  const [{ onChange }, { value }] = useField(fieldId);
  return <input onChange={e => onChange(e.target.value)} value={value} />
}

useField包含更多类似onBlur,…来管理字段的状态。该字段不会对您是否在web环境中做出任何假设,因此可以在react-native…中使用它。

如果我们想用自己的名字来命名,那我们就要做<TextField fieldId="name" />,我们很好!

在这里阅读有关此钩子的更多信息

如果我们想管理我们的friends领域useFieldArray,我们将为您服务。

const Friends = () => {
  const [{ add }, { value: friends }] = useFieldArray('friends');
  return (
    <React.Fragment>
      {friends.map((friend, index) => (
        <div>
          <TextField fieldId={`friends[${i}].name`} />
          <button onClick={() => remove(i)}>Unfriend</button>
        </div>
      )}
      <button onClick={() => add({ id: friends.length })}>Add friend</button>
    </React.Fragment>
  )
}

在这里阅读有关此钩子的更多信息

所有这一切都应该由您来设置,以管理您的朋友和您自己的名字,您可以在此处查看该示例。

开发者经验

我们有一个非常著名的方法,即用于受控字段的Form-Field方法,该方法工作得很好并且感觉非常直观。我们在一个中心位置控制我们的状态,Form并通过React.contextProvider。一个字段可以选择加入某个特定的字段,并针对该特定字段挂钩错误。

我意识到,在某些情况下,您想对另一个字段中的更改做出反应,并针对此更改当前或可能的值。在v4之前,必须添加另一个useField在该字段useFormConnect上侦听的侦听器,甚至添加一个侦听整个表单状态并手动检查所有内容的侦听器。
幸运的是,在v4中,我们有一个解决方案,称为useSpy

您可以在此处阅读有关useFormConnect的更多信息。

让我们看一个例子:

import { useField, useSpy } from 'hooked-form';

const optionsForAMinor = [...];
const regularOptions = [...];

const MySelect = () => {
  const [options, setOptions] = useState(optionsForAMinor);
  const [{ setFieldValue }, { value }] = useField('selectField');

  useSpy('age', (newAge) => {
    if (newAge >= 18) {
      setOptions(regularOptions);
    } else {
      setOptions(optionsForAMinor);
    }
  });

  return <Select options={options} value={value} onChange={setFieldValue} />
}

每当我们的年龄改变时,我们都可以更改选项,而不必useField在一个字段中混合使用多个钩子。

你可以在这里阅读更多有关钩子的信息

尺寸+性能

在此之前,当值更改时,Provider它将检查需要更新哪些钩子,并从Provider更新的React版本中的钩子中进行更新,这将触发一条console.warn说法,即父母无法更新孩子。

这使我重新考虑如何处理组件的传播更新,我们使用中calculateChangedBits提供的React.createContext表示我们永远不想处理转售,因此其价值变为() => 0。如果您不熟悉此API,请在此处阅读更多信息

这意味着对上下文值的更新将永远不会触发任何渲染,这不是我们想要的,但是它提高了性能,因为在正常的上下文情况下,useContext即使更改的部分与它们无关,它也会触发每个渲染。

下一步是制作一个小的事件发射器,该事件发射器将在每个字段上注册。我们有一个“主题”,我们可以在每个字段上以的形式收听fieldId,这应该绰绰有余。
每个人都useField将使用fieldId提供的参数将自己注册到发射器。当错误触发更改时,…它将查看已更改的部件并发出fieldIds引起这些挂钩的渲染的相关信息。

这种紧凑的发射器减少了200Bytes的大小。

总结

我希望我成功改善了开发人员体验,性能和尺寸方面对我来说似乎有所改善。

如果您喜欢图书馆,请别忘了⭐️仓库,这意味着很多!

让我知道您在评论中的想法或发给我

useSpy的奖励示例:https ://codesandbox.io/s/admiring-vaughan-u2lzt

未经允许不得转载:WEB开发编程网 » Hooked-Form v4
微信扫码关注微信公众号

WEB开发编程网

谢谢支持,我们一直在努力

安全提示:您正在对WEB开发编程网进行赞赏操作,一但支付,不可返还。