我的编程空间,编程开发者的网络收藏夹
学习永远不晚

React项目中hook实现展示对话框功能

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

React项目中hook实现展示对话框功能

React中使用对话框并不容易,主要因为:

  1. 对话框需要在父组件中声明,才能在子组件中控制其是否显示
  2. 给对话框传递参数只能由props传入,这意味着所有状态管理都必须在更高阶的组件中。而实际上这个对话框的参数只在子组件中才会维护。这时就需要我们使用自定义事件将参数传回

这些问题的本质就是:如何用一个统一的方式去管理对话框,从而让对话框相关的业务逻辑更加模块化,以及和其他业务逻辑进行解耦。

下面的方式只是经验总结,并不是唯一或者最佳实现:

思路:使用全局状态管理所有对话框

对话框本质上是独立于其他界面的一个窗口,用于完成一个独立的功能。

所以,定义一个对话框,定位等价于定义一个具有唯一URL路径的页面。只是前者由弹出层实现,后者是页面的切换。

对话框UI弹出过程和页面URL的切换非常类似,那么我们就可以给每一个对话框定义一个全局唯一的ID,然后通过这个ID去显示或者隐藏一个对话框,并且给它传递参数。

尝试设计一个API去做对话框的全局管理

假设我们实现的对话框为NiceModal,那么我们的目标是如下去使用:

const UserInfoModal = NiceModal.create(
    'user-info-modal',
    RealUserInfoModal
)
 
// 创建一个useNiceModal 这样的hook去获取某个id的对话框的操作对象
const modal = useNiceModal('user-info-modal')
 
// 通过 modal.show 显示一个对话框,并能够给它传递参数
modal.show(args)
modal.hide()

可以看到,如果有这样的API,那么无论在哪个层级的组件,只要知道某个Modal的ID,那么就都可以统一使用这些对话框,而不再需要考虑该在哪个层级的组件去定义了。

实现:创建NiceModal组件和相关API

创建一个处理所有对话框的action creator 和 reducer

function showModal(modalId, args) {
    return {
        type: "nice-modal/show",
        payload: {
            modalId,
            args
        }
    }
}
 
function hideModal(modalId, force) {
    return {
        type: "nice-modal/hide",
        payload: {
            modalId,
            force
        }
    }
}
const modalReducer = (state = { hiding: {} }, action) {
    switch (action.type) {
        case "nice-modal/show":
            const {modalId, args} = action.payload
            return {
                ...state,
                // 如果存在 modalId 对应的状态(即args),就显示这个对话框
                // 只要有参数就认为对话框应该显示,如果没有传递args,在reducer中使用默认值true
                [modalId]: args || true,
                // 定义一个hiding 状态, 用于处理对话框关闭动画
                hiding: {
                    ...state.hiding,
                    [modalId]: false,
                }
            }
        case "nice-modal/hide":
            const { modalId, force: boolean } = action.payload
            // 只有force时才真正移除对话框,否则就是隐藏中hiding
            return action.payload.force 
                ? {
                    ...state,
                    [modalId]: false,
                    hiding: { [modalId]: false }
                  }
                : { ...state, hiding: { [modalId]: true } }
            default:
                return state
    }
}

这段代码的主要思路就是通过Redux的store去存储每个对话框状态和参数。在这里设计了两个action,分别显示和隐藏对话框。

特别注意的是,这里加入了hiding这样的一个状态,用来处理对话框关闭过程动画。

根据使用顺序,首先实现 createNiceModal,

使用容器模式,在对话框不可见时直接返回null,从而不渲染任何内容,

确保即使页面上定义了100个对话框,也不会影响性能。

createNiceModal = (modalId, Comp) => {
    return (props) => {
        const { visible, args } = useNiceModal(modalId)
        if (!visible) return null
        return <Comp {...args} {...props} />
    }
}
 
// 使用
const MyModal = createNiceModal('my-modal', () => {
    return (
        <NiceModal id="my-modal" title="Nice modal">
            Hello NiceModal
        </NiceModal>
    )
})

实现useNiceModal,根据id,封装一些逻辑。

让Redux的action使用起来更方便,在其内部封装对store的操作,从而实现对话框状态管理的逻辑重用。

const modalCallbacks = {}
 
const useNiceModal = (modalId) => {
    const dispatch = useDispatch()
 
    // 封装Redux action 用于显示对话框
    const show = useCallback(
        (args) => {
            dispatch(showModal(modalId, args))
        },
        [dispatch, modalId]
    )
    
    // 封装Redux action 用于隐藏对话框 (force: boolean)
    const hide = useCallback(
        (force) => {
            dispatch(hideModal(modalId, force))
        },
        [dispatch, modalId]
    )
 
    const args = useSelector((s) => s[modalId])
    const hiding = useSelector((s) => s.hiding[modalId])
 
    // 只要有参数就认为对话框应该显示,如果没有传递args,在reducer中使用默认值true
    return { args, hiding, visible: !!args, show, hide }
}

这样,我们就实现了一个NiceModal这样的全局对话管理框架。

这样使用:

import { Button } from 'antd'
import NiceModal, {
    createNiceModal,
    useNiceModal
} from "./NiceModal"
 
const MyModal = createNiceModal("my-modal", () => {
    return (
        <NiceModal id="my-modal" title="Nice Modal">
            Hello World
        </NiceModal>
    )
})
 
function MyModalExample() {
    const modal = useNiceModal("my-modal")
    return (
        <>
            <Button type="primary" onClick={() => modal.show()}>
                Show my modal
            </Button>
            <MyModal />
        </>
    )
}

处理对话框的返回值

如果说对话框和页面这两种UI模式基本上是一致的,都是独立窗口完成独立逻辑。但是在用户交互上,有一定的差别:

  • 对话框可能需要返回值给调用者
  • 而页面切换一般不会关心页面执行的结果是什么

基于上面的NiceModal实现逻辑,现在考虑如何让调用者获得返回值。

我们可以把用户在对话框中的操作看成一个异步操作逻辑,那么用户在完成对话框中内容的操作后,就认为异步操作逻辑完成了。因此我们可以利用Promise来完成这样的逻辑。

那么,我们要实现的API如下:

const modal = useNiceModal('my-modal')
// 实现一个 promise API 来处理返回值
modal.show(args).then(res => {})

事实上,要实现这样一个机制并不困难,就是在 useNiceModal 这个 Hook 的实现中提供一个 modal.resolve 这样的方法,能够去 resolve modal.show 返回的 Promise。

代码的核心思路就是将show 和 resolve 两个函数通过 Promise 联系起来。因此两个函数调用位置不一样,所以我们使用一个局部的临时变量,来存放resolve回调函数。

// 使用一个 object 缓存 promise 的 resolve 回调函数
const modalCallbacks = {};
export const useNiceModal = (modalId) => {
  const dispatch = useDispatch();
  const show = useCallback(
    (args) => {
      return new Promise((resolve) => {
        // 显示对话框时,返回 promise 并且将 resolve 方法临时存起来
        modalCallbacks[modalId] = resolve;
        dispatch(showModal(modalId, args));
      });
    },
    [dispatch, modalId],
  );
  const resolve = useCallback(
    (args) => {
      if (modalCallbacks[modalId]) {
        // 如果存在 resolve 回调函数,那么就调用
        modalCallbacks[modalId](args);
        // 确保只能 resolve 一次
        delete modalCallbacks[modalId];
      }
    },
    [modalId],
  );
  
  // 其它逻辑...
 
  // 将 resolve 也作为返回值的一部分
  return { show, hide, resolve, visible, hiding };
};

总结

到此这篇关于React项目中hook实现展示对话框功能的文章就介绍到这了,更多相关React hook展示对话框内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

React项目中hook实现展示对话框功能

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

React项目中hook怎么实现展示对话框功能

这篇文章主要介绍“React项目中hook怎么实现展示对话框功能”,在日常操作中,相信很多人在React项目中hook怎么实现展示对话框功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”React项目中hoo
2023-06-30

如何在Android中利用Dialog实现一个对话框功能

今天就跟大家聊聊有关如何在Android中利用Dialog实现一个对话框功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。一、普通对话框AlertDialog.Builder bui
2023-05-31

Android开发中怎么实现一个对话框交互功能

本篇文章给大家分享的是有关Android开发中怎么实现一个对话框交互功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1. 在Android SDK中,虽然有许多的窗口,有些类
2023-05-31

react项目中使用react-dnd实现列表的拖拽排序功能

这篇文章主要介绍了react项目中使用react-dnd实现列表的拖拽排序,本文结合实例代码讲解react-dnd是如何实现,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-02-06

在Android应用中使用AlertDialog对话框可以实现哪些功能

今天就跟大家聊聊有关在Android应用中使用AlertDialog对话框可以实现哪些功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。常用的Dialog有确认对话框,单选按钮对话框
2023-05-31

怎么在Android应用中利用控件实现一个对话框功能

怎么在Android应用中利用控件实现一个对话框功能?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1、自定义提示对话框DialogM.Builder builder = new
2023-05-31

Android开发中项目实现一个显示输入密码的功能

Android开发中项目实现一个显示输入密码的功能?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。具体如下:main.xml:
2023-05-31

如何在Python项目中利用Django框架实现一个支付宝付款功能

今天就跟大家聊聊有关如何在Python项目中利用Django框架实现一个支付宝付款功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。建立一个Django项目然后在里面创建一个应用,如
2023-06-06

编程热搜

目录