-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NiceModal:重新思考 React 中的弹窗使用方式 #16
Comments
在中后台业务中归纳出这样的方法,将组件 promise 化: function promisify(Render) {
return new Promise((res, rej) => {
const div = document.createElement('div')
document.body.appendChild(div)
ReactDOM.render(
<Render
destroy={val => {
if (val) res(val)
else rej()
ReactDOM.unmountComponentAtNode(div)
document.body.removeChild(div)
}}
/>,
div
)
})
} |
这个方法很赞!我们也有类似的工具函数,对于 99% 场景都足够了(也没遇到无法支撑的场景),主要是去年看到了 NiceModal,调用方式更加灵活,也解决了 Context 问题,就换 NiceModal 了。 |
以前的我:这样写是不是违反了 React 伦理,会不会坏了祖师爷立下的规矩 |
这个挂载 body 可能会有问题哦,比如在微前端的场景下,看看是不是应该弄一个类似 antd 的 getPopupContainer |
@enclairfarron indeed |
我发现很多同学对 |
在开始进入正题之前,先看看一些与弹窗有关的有趣场景 🤔。
一些有趣的真实场景
案例一:全局弹窗
上图是掘金的登录弹窗,未登录状态下触发该弹窗展示的时机有很多,比如:
开发者往往会基于第三方组件库定义一个
<LoginModal />
,然后将其挂载至Root
组件下:这样会带来一些问题:
<LoginModal />
内部逻辑在组件渲染的时候就会执行,即使弹窗处于隐藏状态setVisible
以及setOtherLoginData
透传至<Main />
内部的多个子组件,你可以选择通过 props 一层一层的传递进去(鬼知道有多少层!),也可以引入工具进行状态共享,但不论怎样,这都不是一件容易的事;展示一个弹窗,为什么会变得如此复杂?
除了上述全局弹窗的场景,还有一种场景也很让人头疼。
案例二:存在分支以及依赖关系的弹窗
弹窗 1 确认弹出弹窗 2,取消则弹出弹窗 3,弹窗 2 以及 弹窗 3 也存在对应的分支逻辑,子孙满堂轻而易举,若按照常规声明式弹窗组件的实现,非常恐怖!
不那么通用的解决方案
摆脱所谓的 React 哲学:数据驱动视图(
view = f(data)
),回归原始的window.confirm
以及window.alert
,很多问题迎刃而解:经过以上代码处理,可以直接通过
LoginModal.show({otherLoginData})
展示弹窗(hide
以及destroy
同理)。对于存在依赖关系的弹窗,则可以通过返回
Promise
进行链式调用,使用方式如下,此处不过多展开。由于该方案是通过
ReactDOM.render
将组件渲染到一个新节点,脱离了原始的 React 上下文,在某些强依赖Context
的场景会显得有些麻烦。可能是最好的弹窗实践
某天在逛 github 的时候发现了
@ebay/nice-modal-react
,让我们看看 ebay 的开发者是如何让弹窗在 React 下变得足够 Nice。创建弹窗
和原先基于 antd 自定义一个弹窗组件非常相似,只不过弹窗显隐相关的
props
(如visible/hide/remove
) 是通过useModal
获取,最外层则通过NiceModal.create
将组件进行一层封装(高阶组件)。使用弹窗
在使用弹窗之前,需要在
Root
节点引入<NiceModal.Provider />
随后便可在任意地方通过
NiceModal.show
展示先前自定义的弹窗:经过
NiceModal
的封装,好处显而易见:Provider
下)show/hide
方法返回值为Promise
,方便链式调用(通过useModal().resolve(val)
等方法改变Promise
状态)简单实现思路
如果你对 NiceModal 的实现原理有兴趣,那么可以思考一下我们之前的痛点是什么?案例一中描述了两大主要痛点:
NiceModal.Provider
内统一渲染弹窗show/hide/useModal
)暴露理解上述三个方法后,
show/hide/useModal
等方法就是基于dispatch
函数进行弹窗数据(Context
) 的更新从而触发视图更新(其中show
方法多一步注册,生成 ID 并绑定至对应的高阶组件)。推荐阅读
The text was updated successfully, but these errors were encountered: