react Hook+antd封装一个优雅的弹窗组件

这篇具有很好参考价值的文章主要介绍了react Hook+antd封装一个优雅的弹窗组件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

在之前学vue2的时候封装过一个全局的弹窗组件,可以全局任意地方通过this调用,这次大创项目是用react技术栈,看了一下项目需求,突然发现弹窗还是比较多的,主要分为基础的弹窗以及form表单式的弹窗,如果只是无脑的去写代码,那些项目也没啥必要了。正好react和hook相结合,去实现一个全局的弹窗组件,便于之后的使用。

心血历程

antd组件的弹窗一般是和我们的代码放一起的,这样就导致复用性比较低,而且也显得代码比较乱。由此我就想过自己封装一个,有了之前使用vue封装的经验,我开始着手封装,基本思路就是创建一个新的div放到页面中,手动的渲染与删除,确定和取消按钮正好对应promise的成功与失败。基本思路没有问题,但是再实行的过程中,首先遇到手动渲染挂载到页面的问题,之后又遇到逻辑放到一起,无法手动控制form表单,最后突然想清楚一点就是,逻辑可以分开,把一个功能的相同点与不同点进行分离,逻辑上要单纯,最后再整合到一起。这样的话可以专注于具体的逻辑功能及实现。

代码
modal.tsx

封装的弹窗具体功能,其中根据类型的不同会用到form的高阶组件

import React, { useCallback, useEffect } from "react";
import ReactDOM from "react-dom/client";
import { Button, Modal } from "antd";
import { useState } from "react";
import { useForm } from "./form";
type PromiseType = {
  resolve?: any;
  reject?: any;
};
// modal类型(分为普通或者表单形式)
type modalType = "nomal" | "form";
/* 
成功之后的回调函数
显示标题
提示文字(用于普通类型文本提示)
成功文字
配置对象(字段名,规则,默认值)
*/
type modalPropsType = {
  type?: modalType;
  title?: string;
  infoTxt?: string;
  okTxt?: string;
  successCallback?: (values?: any) => void;
  formOptions?: any;
};

export const useModal = (props: modalPropsType = {}) => {
  const {
    type = "nomal",
    title = "提示",
    infoTxt = "这是一段提示",
    okTxt = "确定",
    successCallback = () => {},
    formOptions = [],
  } = props;
  const [show, setShow] = useState<boolean>(false);
  const [promiseRes, setPromiseRes] = useState<PromiseType>();
  const [containerEle, setContainerEle] = useState<HTMLElement | null>(null);
  // 节点的挂载与卸载
  useEffect(() => {
    if (containerEle) {
      return;
    }
    // 创建挂载节点
    const div = document.createElement("div");
    div.id = "myContainer";
    document.body.append(div);
    setContainerEle(div);
  }, [containerEle]);
  // 卸载节点
  const unMounted = useCallback(() => {
    if (containerEle) {
      document.body.removeChild(containerEle);
      setContainerEle(null);
    }
  }, [containerEle]);

  const success = useCallback(
    (values: any) => {
      successCallback && successCallback();
      promiseRes?.resolve(type === "nomal" ? "确定" : values);
      setShow(false);
      unMounted();
    },
    [promiseRes, unMounted, successCallback, type],
  );
  // 取消
  const cancel = useCallback(() => {
    promiseRes?.reject("取消");
    setShow(false);
    unMounted();
  }, [unMounted, promiseRes]);
  // 获取包装节点
  const { MyForm } = useForm({ cancel, success, okTxt, options: formOptions });
  // 挂载节点
  useEffect(() => {
    if (!show || !containerEle) {
      return;
    }
    const root = ReactDOM.createRoot(containerEle as HTMLElement);
    // 根据类型,去判断是简单的弹窗还是form表单
    root.render(
      <Modal
        onCancel={cancel}
        open={show}
        onOk={success}
        destroyOnClose={true}
        title={title}
        okText={okTxt}
        wrapClassName="modal-wrap"
        cancelButtonProps={{ shape: "round" }}
        okButtonProps={{ shape: "round" }}
        width={600}
        footer={
          type === "form"
          ? null
          : [
            <Button key="success" type="primary" onClick={success}>
              {okTxt}
            </Button>,
            <Button key="cancel" onClick={cancel}>
              取消
            </Button>,
          ]
        }
        getContainer={containerEle as HTMLElement}
        >
        {type === "form" && <MyForm></MyForm>}
        {type === "nomal" && <p>{infoTxt}</p>}
      </Modal>,
    );
  }, [
    show,
    MyForm,
    cancel,
    containerEle,
    title,
    infoTxt,
    okTxt,
    success,
    type,
  ]);
  // 初始化
  const init = () => {
    setShow(true);
    return new Promise((resolve, reject) => {
      setPromiseRes({ resolve, reject });
    });
  };
  return { init };
};
from.tsx

封装的form表单(待完善)

import { Button, Form, FormInstance, Input, Space } from "antd";
import React from "react";
import { useCallback } from "react";

/* 
传递配置对象()
1. 成功回调
2.失败回调
3.配置对象(自动生成form表单)
*/
type formProp = {
  success: (values: any) => void;
  cancel: () => void;
  okTxt: string;
  options?: any;
};

type FieldType = {
  username?: string;
  password?: string;
  remember?: string;
};
export const useForm = (formProp: formProp) => {
  const { success, cancel, okTxt } = formProp;
  const MyForm = () => {
    const formRef = React.useRef<FormInstance>(null);
    const onFinish = useCallback((values: any) => {
      console.log(values);
      success(values);
    }, []);
    const onFinishFailed = useCallback((values: any) => {
      console.log(values);
    }, []);
    const onReset = () => {
      formRef.current?.resetFields();
    };
    return (
      <Form
        ref={formRef}
        labelCol={{ span: 8 }}
        wrapperCol={{ span: 16 }}
        style={{ maxWidth: 600 }}
        initialValues={{ remember: true }}
        autoComplete="off"
        onFinish={onFinish}
        onFinishFailed={onFinishFailed}
        >
        <Form.Item<FieldType>
          label="Username"
          name="username"
          rules={[{ required: true, message: "Please input your username!" }]}
          >
          <Input />
        </Form.Item>

        <Form.Item<FieldType>
          label="Password"
          name="password"
          rules={[{ required: true, message: "Please input your password!" }]}
          >
          <Input.Password />
        </Form.Item>

        <Form.Item wrapperCol={{ offset: 8, span: 16 }}>
          <Space wrap>
            <Button type="primary" htmlType="submit">
              {okTxt}
            </Button>
            <Button danger htmlType="button" onClick={onReset}>
              重置
            </Button>
            <Button onClick={cancel}>取消</Button>
          </Space>
        </Form.Item>
      </Form>
    );
  };

  return {
    MyForm,
  };
};

使用
//可以传递type来指定类型
const nomalMadal=useModal()
//执行该函数开启弹窗
const show=()=>{
  nomalMadal.init()
    .then((res) => {
      console.log("确定", res);
    })
    .catch((err) => {
      console.log("取消", err);
    });
}
总结

在之后的学习过程中,要多换思路,不必拘谨于一个点,要把思维发散,逻辑可以多种方法实现,还有就是源码的能力,之后要多学一下源码,了解源码的思想还有实现方法,这样才能更好的玩转第三方库,如果只是简单的使用,那一个小白,培训个几个月也能达到使用的程度,要有自己的见解和自己的优势。文章来源地址https://www.toymoban.com/news/detail-645649.html

到了这里,关于react Hook+antd封装一个优雅的弹窗组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • React + Typescript + Antd:封装通用的字典组件DXSelect

    在开发中,我们经常遇到这样的场景,在表单中,有个下拉框,选择对应的数据。 那么这个下拉框的选项,就是字典。一搬的做法是,通过antd的Select来实现,代码如下:

    2024年02月15日
    浏览(60)
  • react18+antd5.x(1):Notification组件的二次封装

    antdesign已经给我们提供了很好的组件使用体验,但是我们还需要根据自己的项目业务进行更好的封装,减少我们的代码量,提升开发体验 开起来和官网的使用没什么区别,但是我们在使用的时候,进行了二次封装,更利于我们进行开发 MyNotification.jsx,是我们的业务页面 Notif

    2024年02月11日
    浏览(32)
  • 【微信小程序】使用weui组件库来实现弹出一个确认的弹窗popup,其中包含图片和名称

    在微信小程序中,你可以使用weui组件库来实现弹出一个确认的popup,并在其中包含图片和名称。以下是一个示例代码: 在wxml文件中,添加一个按钮来触发弹出确认popup: 在wxss文件中,定义确认popup的样式: 在js文件中,编写相应的逻辑来显示和隐藏确认popup,并传递图片和名

    2024年02月17日
    浏览(31)
  • Vue3封装可拖拽的弹窗

    核心代码(复制就可以使用了) 使用方式

    2024年01月19日
    浏览(27)
  • 选择图片的弹窗组件

    2023年04月09日
    浏览(22)
  • 前端(十五)——开源一个用react封装的图片预览组件

    👵博主:小猫娃来啦 👵文章核心:开源一个react封装的图片预览组件 Gitee:点此跳转下载 CSDN:点此跳转下载 装依赖 运行 打开 创建一个React函数组件并命名为 ImageGallery 。 在组件内部,使用useState钩子来定义状态变量,并初始化为合适的初始值。 selectedImageUrl 来追踪当前选

    2024年02月10日
    浏览(41)
  • 【微信小程序】实现点击+号弹出一个附着旁边的弹窗进行多个方式的选择

    在微信小程序中,你可以使用小程序的组件和事件来实现点击+号弹出一个附着在+号旁边的弹窗,以进行多个方式的选择。以下是一个示例代码: 在wxml文件中,创建一个按钮,并为按钮绑定一个点击事件: 在上述代码中,我们创建了一个按钮,用于展示+号图标,并给按钮绑

    2024年02月14日
    浏览(31)
  • React修改Antd组件的样式

    修改默认的antd组件,需要使用 global 修改后Steps样式 为什么需要这样写呢? 因为我们启动了 CSS Modules ,它是一种技术流的组织css代码的策略,它将为css提供默认的局部作用域。因为构建工具会在编译的时候自动把我们的类名加上一个哈希字符串,例如上面我们写的类名为t

    2024年02月11日
    浏览(34)
  • 基于antd@5.x封装Form.List组件

    基于antd@5.x封装Form.List组件 使用案例

    2024年02月16日
    浏览(74)
  • 前端实现简单的sse封装(React hook Vue3)

    所谓的SSE(Sever-Sent Event),就是浏览器向服务器发送了一个HTTP请求,保持长连接,服务器不断单向地向浏览器推送“信息”,这么做是为了节省网络资源,不用一直发请求,建立新连接。 优点:SSE和WebSocket相比,最大的优势是便利,服务端不需要第三方组件,开发难度低,SSE和

    2024年02月09日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包