背景
在项目开发中有一个 Table 表格,每行中有一个操作按钮,点击这个操作按钮弹出一个Modal.confirm
, Modal.confirm
内容是一个输入框,在输入内容后点击确定把输入的内容传递给后端,这是一个相当常见的操作,代码如下:
import { Modal, Button, Input } from 'antd';
import { useState } from 'react';
const ModalTest = () => {
const [text, setText] = useState<string>('');
const edit = () => {
Modal.confirm({
content: (
<Input
value={text}
onChange={({ target: { value } }) => {
setText(value);
}}
/>
),
icon: null,
onOk: async () => {
console.log(text, 'text--');
},
});
};
return (
<div>
{/* 测试对比input */}
<Input
value={text}
onChange={({ target: { value } }) => {
setText(value);
}}
/>
<Button onClick={edit}>编辑</Button>
</div>
);
};
可以发现在 Modal 的 Input
中是无法正常输入内容的,而在测试对比的Input
中则能正常输入。
办法一 ❌
把value={text}
改为defaultValue={text}
能正常输入,但是点击确定之后打印出的text
值不对,总是比输入落后一次。
// ...
Modal.confirm({
content: (
<Input
// value={text}
defaultValue={text}
onChange={({ target: { value } }) => {
setText(value);
}}
/>
),
icon: null,
onOk: async () => {
console.log(text, 'text--');
},
});
// ...
办法二 ❌:
封装一下能不能解决?试了一下还是不行,依然是能输入,但是获取到的数据还是不对
const MyInput = ({ onChange }: any) => {
const [value, setValue] = useState<string>('');
useEffect(() => {
if (onChange) {
onChange(value);
}
}, [value, onChange]);
return (
<Input
value={value}
onChange={({ target: { value } }) => {
setValue(value);
}}
/>
);
};
const ModalTest = () => {
const [text, setText] = useState<string>('');
const onChange = (val: string) => {
setText(val);
};
const edit = () => {
Modal.confirm({
content: <MyInput onChange={onChange} />,
icon: null,
onOk: async () => {
console.log(text, 'text--');
},
});
};
return (
<div>
<Button onClick={edit}>编辑</Button>
</div>
);
};
export default ModalTest;
办法三 ✅
以上方法都不行,根据 state 更新不及时的表现,我推测Modal.confirm
很可能不是一个 React 组件,无法重新渲染,那只能上useRef.current
了:
import { useRef } from 'react';
const ModalTest = () => {
const inputValueRef = useRef<string>('');
const edit = () => {
Modal.confirm({
content: (
<Input
onChange={({ target: { value } }) => {
inputValueRef.current = value;
}}
/>
),
icon: null,
onOk: async () => {
console.log(inputValueRef.current, 'text--');
// 别忘了最后清空
inputValueRef.current = '';
},
});
};
return (
<div>
<Button onClick={edit}>编辑</Button>
</div>
);
};
结果运行正确 👌。
验证
我在 github 上搜了一下,似乎遇到这个问题的人还挺多的,比如:github issue,github issue,github issue
翻源码验证一下自己的想法:
可以看到从定义到实现上都是普通函数,而不是一个组件,因此在里面输入的数据就无法实现更新。
后来在另一个issue里面发现,作者已经解释了问题原因 ⬇️,但是大家似乎都不满意...