手写实现 rc-field-form (四)

1,657 阅读3分钟

「这是我参与2022首次更文挑战的第38天,活动详情查看:2022首次更文挑战」。

写在前面

  • 前面一篇文章,我们实现了自定义 hook useForm 用于方便获取数据仓库的操作权限对象
  • 为了 Form 组件的子孙组件都能获取到同一个数据仓库的操作权限对象,我们选择使用 context API 进行跨层级传递在 Form 组件中获取的数据仓库操作权限对象
  • 下面我们就来实现它

跨层级传递数据仓库的操作权限对象

  • 使用 context 就需要先创建一个 context 对象,下面是实现代码
// FormContext.js

import React from "react";

export const FormContext = React.createContext();
  • 我们新建一个 FormContext.js 文件,然后使用 React.createContext() 方法创建一个 context 对象
  • 有了 context 对象,我们就可以在 Form 组件上将数据仓库操作权限对象传递下去,下面是实现代码
import React from "react";
import { FormContext } from "./FormContext";
import { useForm } from "./useForm";

export default function Form({ children }) {
  const [formStore] = useForm();
  return (
    <form>
      <FormContext.Provider value={formStore}>{children}</FormContext.Provider>
    </form>
  );
}
  • 很简单,我们只需要用 FormContext.Provider 将 children 进行包裹即可
  • context 对象创建好了,也通过 provider 传递下去了,那么我们的 Field 组件就可以使用了

实现 Field 组件

  • 这里我们使用 class 来实现 Field 组件,因此可以使用 static contextType 来获取上层组件传递的 context
  • 下面是实现代码
import React, { Component } from "react";
import { FormContext } from "./FormContext";

export class Field extends Component {
  static contextType = FormContext;

  // 将接收的组件变为受控组件
  getControlled = () => {
    const { name } = this.props;
    const { setFieldValue, getFieldValue } = this.context;

    return {
      value: getFieldValue(name),
      onChange(e) {
        const newVal = e.target.value;
        setFieldValue(name, newVal);
      },
    };
  };

  
  render() {
    const controlledChild = React.cloneElement(
      this.props.children,
      this.getControlled()
    );
    return controlledChild;
  }
}
  • 上面的实现中,最关键的是 getControlled 方法
    • 它根据 Field 组件接受的 props 中的 name 属性
    • 以及获取的 context,也就是数据仓库操作权限对象中的用于单个字段数据的存与取的方法 setFieldValue, getFieldValue
    • 生成一个对象,这个对象的所有属性,就是用来传递给 Field 组件的 children 的 props,也就是数据输入组件
  • 最后 Field 组件的 render 方法返回的是通过 React.cloneElement API 克隆出来的新 React 元素
  • 它接受 getControlled() 的返回值当作 props,所以这个新元素是一个受控组件
  • 它的数据的输入会被接管起来,输入的数据被存入数据仓库,然后通过 getFieldValue 方法从数据仓库中取出来,最后进行渲染

小结

  • 在上面,我们已经实现了 Field 组件的一部分功能
    • 获取顶层 Form 组件传递的数据仓库操作权限对象
    • 将数据仓库操作权限,通过 props 传给 Field 组件的 children,使其成为受控组件
  • 那么数据输入后,Field 组件的 children 如何随即更新渲染呢?
  • 下篇文章,我们来解决这个问题

最后

  • 今天的分享就到这里了,欢迎大家在评论区里面进行讨论 👏。
  • 如果觉得文章写的不错的话,希望大家不要吝惜点赞,大家的鼓励是我分享的最大动力 🥰