凌晨的阿里巴巴
前言
笔者最近在开发项目的过程中,由于老代码组件封装比较深,多层Form.Item嵌套,出现了修改input的值但是不生效的情况,特此记录一下Form.Item的坑.
来个简单
一
import { Form, Input } from "antd";
import { useRef } from "react";
import "./App.css";
function App() {
const formRef = useRef();
return (
<div className="App" name="form">
<Form ref={formRef}>
<Form.Item name="username">
<Input value={12} />
</Form.Item>
</Form>
</div>
);
}
这一串代码input框会显示出12这个值吗?答案是否定的.为何? 因为看看官网的这句话:
被设置了 name 属性的 Form.Item 包装的控件,表单控件会自动添加 value(或 valuePropName 指定的其他属性) onChange(或 trigger 指定的其他属性),数据同步将被 Form 接管,这
也就是说你在Form.item里面设置value是无效的.那么要怎么样才能生效呢? setFieldsValue
二
import { Form, Input } from "antd";
import { useRef } from "react";
import "./App.css";
function App() {
const formRef = useRef();
formRef.current.setFieldsValue({
username: 23,
});
return (
<div className="App" name="form">
<Form ref={formRef}>
<Form.Item name="username">
<Input value={12} />
</Form.Item>
</Form>
</div>
);
}
到这没毛病吧.
假如你中间加了一层别的元素呢?
三
import { Form, Input } from "antd";
import { useRef } from "react";
import "./App.css";
function App() {
const formRef = useRef();
formRef.current.setFieldsValue({
username: 23,
});
return (
<div className="App" name="form">
<Form ref={formRef}>
<Form.Item name="username">
<div>
<Input value={12} />
</div>
</Form.Item>
</Form>
</div>
);
}
答案是显示12还是23? ----> 12
也就是说Input不在Form.Item紧跟的子元素的时候,input变成了自己受控了,不受Form的控制了.
原因就是Form.Item只会给他紧跟的子元素增加value和onChange属性,这时候给Div设置value和onChange,就算把value改成了23,有用吗!
那么假如我们封装一个组件呢?
四
function App() {
const formRef = useRef();
if (formRef.current) {
formRef.current.setFieldsValue({
username: 23,
});
}
return (
<div className="App" name="form">
<Form ref={formRef}>
<Form.Item name="username">
<InputTest />
</Form.Item>
</Form>
</div>
);
}
const InputTest = (props) => {
return <Input value={12} />;
};
答案是显示12还是23? ----> 12
那么我们知道了.他是会给InputTest这个组件的props增加value和onChange方法,但是Input的value还是自己设置的12,props的value和onChange我们也没使用,因为setFieldsValue也无效.我们打印props看看!
果然,他默认就有value和onChange.就是antd默认加上的.
如果我们单独封装的组件想不自己设置value和onChange,交给antd保管,那么需要这样写!
五
function App() {
const formRef = useRef();
setTimeout(() => {
if (formRef.current) {
formRef.current.setFieldsValue({
username: 23,
});
}
}, 1000);
return (
<div className="App" name="form">
<Form ref={formRef}>
<Form.Item name="username">
<InputTest value={12} />
</Form.Item>
</Form>
</div>
);
}
const InputTest = (props) => {
console.log("props", props);
return <Input {...props} />;
};
将value和onChange透传给input,这样就能实现Input被antd受控的效果,这时候显示什么?
此处答案是显示12还是23? ----> 23 因为被antd重新赋值了value为23 覆盖了你传的value
六
function App() {
const formRef = useRef();
setTimeout(() => {
if (formRef.current) {
formRef.current.setFieldsValue({
username: 23,
});
}
}, 1000);
return (
<div className="App" name="form">
<Form ref={formRef}>
<Form.Item name="username">
<InputTest />
</Form.Item>
</Form>
</div>
);
}
const InputTest = (props) => {
console.log("props", props);
return <Input {...props} value={12} />;
};
这样呢?
此处答案是显示12还是23? ----> 12 . 因为props里有value=23,但是被你后面设置的value=12覆盖了
七
function App() {
const formRef = useRef();
setTimeout(() => {
if (formRef.current) {
formRef.current.setFieldsValue({
username: 23,
});
}
}, 1000);
return (
<div className="App" name="form">
<Form ref={formRef}>
<Form.Item name="username">
<InputTest />
</Form.Item>
</Form>
</div>
);
}
const InputTest = (props) => {
console.log("props", props);
return <Input value={12} {...props} />;
};
这样呢?
此处答案是显示12还是23? ----> 23 . 因为props里有value=23,覆盖了你写的value=12
看完value我们再看看onChange! 直接输入值会打印1吗?
八
function App() {
const formRef = useRef();
setTimeout(() => {
if (formRef.current) {
formRef.current.setFieldsValue({
username: 23,
});
}
}, 1000);
const handleChange = () => {
console.log("1");
};
return (
<div className="App" name="form">
<Form ref={formRef}>
<Form.Item name="username">
<Input onChange={handleChange} />
</Form.Item>
</Form>
</div>
);
}
答案是会! 是不是和value不一样了,value是会覆盖的,但是onChange是不会被覆盖的
自己写的组件呢?
九
function App() {
const formRef = useRef();
setTimeout(() => {
if (formRef.current) {
formRef.current.setFieldsValue({
username: 23,
});
}
}, 1000);
const handleChange = () => {
console.log("1");
};
return (
<div className="App" name="form">
<Form ref={formRef}>
<Form.Item name="username">
<InputTest onChange={handleChange} />
</Form.Item>
</Form>
</div>
);
}
const InputTest = (props) => {
console.log("props", props);
return <Input />;
};
答案是不会! 因为input上都没OnChange方式你得透传props进去或者自己写onChange
十
const InputTest = (props) => {
console.log("props", props);
return <Input {...props} />;
return <Input onChange={xx} />;
};
总结
大白话:1.Form.item会给紧跟的子元素加上value和onChange属性 2.value会覆盖,onChange不会覆盖.
原项目代码比这复杂的多,搭建个demo看的更清楚了!❤️