Modal.confirm okText,cancelText 默认是中文。
但是开发中偶然是英文,刷新页面恢复中文。
问题复现
以下复现以及代码分析, antd 是 4.14.1
经过测试发现,在两个组件(ComponentA和ComponentA)均使用 Modal.confirm 创建弹窗情况,如下:
// ComponentA
import React, { useState } from 'react';
import { Button, Modal} from 'antd';
const showModal = () => ( Modal.confirm({content:'confirm' }))
return (
<>
<Button type="primary" onClick={showModal}> Modal </Button>
</> );
按照如下步骤复现
- ComponentA 通过
Modal.confirm触发弹窗提示, - 卸载 ComponentA
- 触发ComponentB弹窗 okText,cancelText 是英文
- 刷新(重新渲染ComponentB),ComponentB 弹窗 okText,cancelText 恢复中文
总的来说,使用 Modal.confirm 的组件在卸载后,此时没有重新渲染的组件使用 Modal.confirm okText,cancelText 默认为英文。
问题原因
根本原因: ConfigProvider 中locale 属性配置错误或者失效。
这里可以参考:
前置背景
首先,官网对locale 属性的定义如下:
从 ConfigProvider 实现中可知locale 状态通过 LocaleReceiver 管理
在 LocaleReceiver 实现中,没有设置defaultLocale(即上图的legacyLocale)时,locale 是英文标准 (locale/en_US)
通常在需求开发中,一个项目只有一个 ConfigProvider来统一 antd 组件配置 ,都会把 locale 属性设置为中文语言包,如下:
import zhCN from 'antd/locale/zh_CN';
<ConfigProvider locale={zhCN}>
<Page />
</ConfigProvider>
也就是在开发中,所有 antd 组件的 ConfigProvider 默认都是同一个。
排除一些在组件内使用ConfigProvider 自定义属性,例如下面外层的 ConfigProvider 仅在 Page1 生效,Page2 获取的配置来自于内层 ConfigProvider
<ConfigProvider locale={zhCN}>
<Page1 />
<ConfigProvider locale={zhCN}>
<Page2 />
</ConfigProvider>
</ConfigProvider>
原因解析
简单了解ConfigProvider 的locale属性后,来看看,Modal.confirm 触发的弹窗 okText 是如何渲染的?
当我们没有设置 oktText 属性时, 系统会从 getConfirmLocale 方法获取 runtimeLocale,并将runtimeLocale 中的 justokText 赋值给 oktText 属性。
从 getConfirmLocale 的实现中发现, runtimeLocale 默认是英文语言包,其值会通过 getConfirmLocale 改变。
什么时候 runtimeLocale 会发生变化呢?
Modal.confirm 的 LocaleProvider (等价于<ConfigProvider locale /> )组件,在组件的componentDidMount、componentDidUpdate 以及 componentWillUnmount以及 LocaleProvider 创建的时候都会改变相关组件的locale 属性。
其中,在 componentWillUnmount(组件卸载)时,changeComfirmLocale 方法是没有传入参数,而在其他阶段都会传入 ConfigProvider 中的runtimeLocale 配置。
接下来,看看 changeComfirmLocale 方法的实现, changeComfirmLocale 没有入参时,返回的是默认(英文语言包)的组件配置。
这也就不难发现,为什么卸载组件后,其他组件的 modal 文案变为英文,刷新组件后又恢复中文。
解决方案
方案一: 使用 Modal useModal 创建modal实例替换 Modal.confirm(推荐)
antd 官网也这样解释,Modal.confirm方法是使用 ReactDOM.render 重新渲染一个 React 根节点上,和主应用的 React 节点是脱离的。
相反, useModal 创建modal实例,通过 hooks 创建 context 从而获取 contextHolder 的上下文环境(包括 locale 属性)。
如下,
Modal.useModal()创建的每个 modal 都是一个实例对象.
const [modal, contextHolder] = Modal.useModal();
React.useEffect(() => {
modal.confirm({
content:'confirm'
});
}, []);
return <div>{contextHolder}</div>;
方案二: Modal.confirm中配置固定的okText
从前置背景中,我们可以知道Modal.confirm中okText在没有配置时,才会根据 locale 匹配语言包获取默认值。
如下,Modal 一直都会是中文。
Modal.confirm({
title: '确定离开当前弹窗吗?',
okText: '确定',
cancelText: '取消'
)}