Modal.confirm是否违反了React模式分析

 更新时间:2022年08月12日 10:46:09   作者:欲三更  
这篇文章主要为大家介绍了Modal.confirm是否违反了React模式分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

如何评价 Ant Design 这个项目(一个设计语言)?

这是一篇临时起意的文章,我参与了一点上图中的讨论,正好有点时间,索性拉篇文章专门聊聊。

首先说结论:我不认为Modal.confirm以及类似的API是anti-pattern,尽管antd作者 

@偏右悄悄地 也说Modal.confirm“并不符合React哲学”。

什么是“React模式”?

很多人都见过这个公式——

view = f(data)

React确实就是这么运作的。

然而React从来没有建议过,让你的整个应用都这么运作。很显然,一个view=f(data),是涵盖不了前端应用那么多可能性的。那么一个现实中有用的网页,大致应该怎么运作?

看图说话——

这张图我想所有人都能看懂,大部分给你科普前端架构的文章大致都是这么画的,这里只解释两点:

  • 第一,蓝箭头代表状态传递,红箭头代表行为传递。比如vdom,其实就是一堆描述某一时刻html状态的数据,但是经过diff,得到的指导react-dom进行操作的patch,其实描述的是“行为”,用现在时髦的说法叫“副作用”。
  • 红框里面为什么除了data还有timing?timing指的是时机,就是说你什么时候应该渲染,本质上是model那一层告诉你的,React组件不会自己没事儿渲染着玩(先不考虑state)。

图是很美好,然而如果一个网页就这样的话,它除了展示一下画面(还不能做单页),不会有任何用处。所以这个图要完善一下——

经过完善,图里面多了框,就是红框里那个actions,指的是当你点按钮的时候,发生的回调操作。有的框架里面管这个叫action,有的是store的成员函数,还有的比如redux,虽然它有action概念,但其实真正的“action”是在reducer里面实现的。

另外这里又出现了timing(时机),这其实是我最近很喜欢的一个概念。所谓的timing,就是告诉另一个模块“it’s time to do xxx”,trigger(event)是timing,dispatch(action)是timing,甚至直接调用成员函数,其实也是一种timing。

这张图,看起来能干一些事儿了,至少能点按钮刷新数据了,能做单页了。然而我们的网页,并非是只读的,除了展示数据,还要往后台提交数据,或者执行某个具体的功能(比如VScode里点ctrl+s保存,它需要往硬盘里面写文件)。所以还要完善一下——

相对完整的前端应用架构

哎,这个版本看起来有具体功能了,因为除了浏览器html之外,我们还多了个“IO等”,这样那些除了变动html之外的“副作用”,就可以实现了。基本上一个网页的架构,就是这样了。

注意,在这个版本中,Model也可以调用Actions,这是因为有些Model库是响应式的,比如rx,它本身就可以通过subscribe驱动副作用。

到这里,咱们终于可以进正题了。

我在上面的图中花了三个虚线框,中间那个是“React掌管的部分”,也就是建议view=f(data)那部分。我们看下箭头的颜色,Model到View,应该是状态数据(data),View到Actions,应该是行为指令(timing)。

其他两层,天生就不是React掌管的范围,业务模型主要负责维护数据以及数据之间的驱动关系,Side effect backend主要负责实现各种副作用,React的那套模型,在这里帮不上忙——注意,这不代表那两层就完全不能用React,事实上confirm完全可以理解为IO的一种(类比下c语言的scanf)。

也就是说,哪怕一个带有明显数据驱动特色的React项目,也存在很多部分不是数据驱动而是事件驱动的(我更喜欢成为“时机驱动”),这是天经地义的事情,不然你的程序根本写不出来。原因很简单,数据只能驱动出状态,只有时机才能驱动出行为——学过《数电》应该对这一点深有感触。

那么,对于“用户点击删除按钮,弹出确认框,点击确定删除条目,点击取消不做任何操作”这样一个功能——

  • 你觉得他是个状态还是个行为?
  • 你觉得他是时机驱动的还是数据驱动的?

答:它是个行为,时机驱动。

那么,对于一个时机驱动的行为,你非得把它硬坳成一个数据驱动的状态,你不觉得很奇怪吗?

一个comfirm,这么写有什么问题呢(伪代码,忽略一部分保护性代码)?

class FoobarComponent extends React.Component {
  // ...
  async onRemoveBtnClick (id) {
    const yes = await Modal.confirm('确认删除吗?')
    if (!yes) return
    dispatch(actions.remove({ id }))
  }
  render () {
    const { items } = this.props
    return <ul>
      {
        items.map(el => <li key={el.id}>
          <span>{el.name}</span>
          <button onClick={this.onRemoveBtnClick.bind(this, el.id)}>删除</button>
        </li>)
      }
    </ul>
  }
}

那么,为什么有人会觉的这样写是反模式呢?

我觉得可能是因为我们在编写网页的时候,一般都会比较注重纵向分层,却常常忽视横向切分。由于react-router的盛行,基本上我们是在组件这个层面配合前端路由来做横向切分的,但实际上这只是一种特殊情况,如果我们的应用更复杂,我们可能需要这样的结构——

上图中每个模块,都和模块A具有大致相同的结构,各个模块之间的时机和状态,可以通过总线一类的工具来中转。

如果我们写网页的“起手式”就是这样的,那么Modal,可能会被设计成一个单独的模块M,Modal.comfirm,可能会被设计成这样:

const yes = await globalBus.dispachAndWait(Actions.comfirm('确认删除吗?'))

这样,你还会觉得“反模式”吗?

PS:为什么为这件小事儿啰嗦这么一大篇文章呢?其实这本来也是我2018年前端技术总结的一部分想法,只是临时借着这个讨论说出来了。2018年上半年,参与了一个临时前端团队,堆了不少业务表单页面,期间,我跟人强调了无数次“不要无脑数据驱动”,还是有有人非得闪转腾挪用数据驱动和render表达一切,留了一大堆屎给我重构,我这一股无名火憋到现在。

以上就是Modal.confirm是否违反了React模式分析的详细内容,更多关于React模式剖析Modal.confirm的资料请关注脚本之家其它相关文章!

相关文章

  • React钩子函数之useDeferredValue的基本使用示例详解

    React钩子函数之useDeferredValue的基本使用示例详解

    useDeferredValue是React 18中非常有用的一个钩子函数,它可以帮助我们优化渲染性能,并让UI更加流畅,如果你还没有尝试过它,不妨在你的下一个React项目中试一试,这篇文章主要介绍了React钩子函数之useDeferredValue的基本使用,需要的朋友可以参考下
    2023-08-08
  • React使用ref方法与场景介绍

    React使用ref方法与场景介绍

    这篇文章主要介绍了React使用ref方法与场景,React支持给任意组件添加特殊属性。ref属性接受一个回调函数,它在组件被加载或卸载时会立即执行
    2022-10-10
  • React css-in-js基础介绍与应用

    React css-in-js基础介绍与应用

    随着React、Vue等支持组件化的MVVM前端框架越来越流行,在js中直接编写css的技术方案也越来越被大家所接受。为什么前端开发者们更青睐于这些css-in-js的方案呢,下面带你了解它
    2022-09-09
  • React实现一个倒计时hook组件实战示例

    React实现一个倒计时hook组件实战示例

    这篇文章主要为大家介绍了React实现一个倒计时hook组件,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • React Fiber构建beginWork源码解析

    React Fiber构建beginWork源码解析

    这篇文章主要为大家介绍了React Fiber构建beginWork源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • 你知道怎么在 HTML 页面中使用 React吗

    你知道怎么在 HTML 页面中使用 React吗

    这篇文章主要为大家详细介绍了如何在HTML页面中使用 React,使用使用js模块化的方式开发,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • react项目如何使用iconfont的方法步骤

    react项目如何使用iconfont的方法步骤

    这篇文章主要介绍了react项目如何使用iconfont的方法步骤,这里介绍下如何在项目中配置。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • React Hooks如何主动更新Hooks组件

    React Hooks如何主动更新Hooks组件

    这篇文章主要介绍了React Hooks如何主动更新Hooks组件问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • react-router-domV6版本改版踩坑记录

    react-router-domV6版本改版踩坑记录

    这篇文章主要介绍了react-router-domV6版本改版踩坑记录,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • React Router中Link和NavLink的学习心得总结

    React Router中Link和NavLink的学习心得总结

    这篇文章主要介绍了React Router中Link和NavLink的学习心得总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12

最新评论