反应表单元素 onchange 事件在动态生成时不起作用
React form elements onchange event not working when generated dynamically
我正在尝试从数据生成输入列表,并让它们作为受控输入来捕获数据。文本输入似乎被捕获得很好,但是文件输入 onchange 事件出现错误,"TypeError: _this2.handleFileInputChange is not a function"。如果我从箭头函数中取出它,我不会收到错误,但回调仍然不起作用。各位大侠怎么看?
------------编辑------------
实施了将函数定义为箭头函数的建议,这很好,但文件输入似乎仍然没有像其他字段那样触发更改事件。我开始认为这是组件的限制。
还有其他想法吗?谢谢!
import React from "react";
// import { Link } from "gatsby";
import Layout from "../components/layout";
import {Form,InputGroup,Button} from 'bootstrap-4-react'
function camelize(str) {
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function(word, index) {
return index === 0 ? word.toLowerCase() : word.toUpperCase();
}).replace(/\s+/g, '');
}
const formContent = [
["Profile Name","Ex. College soccer profile Spring 2020","text"],
["Player Name", "Ex. Jose Greer", "text"],
["Player Profile Photo", "Ex. Jose Greer", "file"]
]
class ProfileForm extends React.Component {
constructor(props) {
super(props);
this.state = {
profileName: '',
playerName: '',
profileImageFilename: '',
};
}
handleFileInputchange = (e) => {
console.log(e.target.files[0]);
this.setState({profileImageFilename: e.target.files[0].filename})
}
handleInputChange = (e) => {
console.log(e)
this.setState({[e.target]: e.target.value})
}
handleSubmit = (e) => {
console.log(e)
e.preventDefault()
}
createFormGroup(i) {
const title = i[0],
placeholder = i[1],
type = i[2]
const titleCamelCase = camelize(title);
if (type === "file") {
return (
<>
<label key={titleCamelCase + "-label"} htmlFor={titleCamelCase}>
Player Profile Image
</label>
<InputGroup key={titleCamelCase + "-group"} mb="3">
<Form.CustomFile
required
onChange={this.handleFileInputChange}
key={titleCamelCase + "-file"}
id={titleCamelCase}
accept=".jpg, .jpeg, .png"
>
{this.state.profileImageFilename
? this.state.profileImageFilename
: "Choose an image. ( .jpg, .jpeg, .png, .gif )"}
</Form.CustomFile>
</InputGroup>
</>
);
}
return (
<>
<label key={titleCamelCase + "-label"} htmlFor={titleCamelCase}>
{title}
</label>
<Form.Input
key={titleCamelCase + "-input"}
mb="3"
required
type={type}
id={titleCamelCase}
placeholder={placeholder}
onChange={this.handleInputChange}
valule={this.state[titleCamelCase]}
/>
</>
);
}
render() {
return (
<Layout>
<Form onSubmit={this.handleSubmit}>
<Form.Group>
{/* {formContent.map(function(i){this.createFormGroup(i)}.bind(this))} */}
{formContent.map((i)=>this.createFormGroup(i))}
</Form.Group>
<Button primary type="submit">
Submit
</Button>
</Form>
</Layout>
);
}
}
export default ProfileForm
问题
class 组件的 this
未绑定到 handleFileInputchange
回调处理程序。
解决方案
您应该在 constructor
中将 this
绑定到 handleFileInputchange
或将其声明为箭头函数。
constructor(props) {
super(props);
this.state = {
profileName: '',
playerName: '',
profileImageFilename: '',
};
this.handleFileInputchange = this.handleFileInputchange.bind(this);
}
或
handleFileInputchange = (e) => {
console.log(e);
this.setState({ profileImageFilename: e.target.file[0].filename });
}
您还可以安全地删除匿名回调并直接传递 this.handleFileInputChange
,因为 onChange
事件处理程序和您的回调具有相同的函数签名:
onChange={this.handleFileInputChange}
更新
我用你的代码创建了一个 codesandbox。奇怪的是,我也没有看到任何 onChange 回调触发(控制台日志),我什至添加了一个 componentDidUpdate
来记录状态更新,这也没有触发。我可以添加一个新文件并看到带有我选择的文件名的文本工具提示,但 UI 中没有任何更新。如果您的 bootstrap 输入仍然导致问题,我建议实施原始输入元素。
@drew 我最终不得不使用 标准输入 元素,因为我找不到任何证据表明反应 bootstrap 组件触发了更改事件。谢谢您的意见。您可能需要修改您的答案,因为正确的部分已在您的评论中。
我正在尝试从数据生成输入列表,并让它们作为受控输入来捕获数据。文本输入似乎被捕获得很好,但是文件输入 onchange 事件出现错误,"TypeError: _this2.handleFileInputChange is not a function"。如果我从箭头函数中取出它,我不会收到错误,但回调仍然不起作用。各位大侠怎么看?
------------编辑------------
实施了将函数定义为箭头函数的建议,这很好,但文件输入似乎仍然没有像其他字段那样触发更改事件。我开始认为这是组件的限制。
还有其他想法吗?谢谢!
import React from "react";
// import { Link } from "gatsby";
import Layout from "../components/layout";
import {Form,InputGroup,Button} from 'bootstrap-4-react'
function camelize(str) {
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function(word, index) {
return index === 0 ? word.toLowerCase() : word.toUpperCase();
}).replace(/\s+/g, '');
}
const formContent = [
["Profile Name","Ex. College soccer profile Spring 2020","text"],
["Player Name", "Ex. Jose Greer", "text"],
["Player Profile Photo", "Ex. Jose Greer", "file"]
]
class ProfileForm extends React.Component {
constructor(props) {
super(props);
this.state = {
profileName: '',
playerName: '',
profileImageFilename: '',
};
}
handleFileInputchange = (e) => {
console.log(e.target.files[0]);
this.setState({profileImageFilename: e.target.files[0].filename})
}
handleInputChange = (e) => {
console.log(e)
this.setState({[e.target]: e.target.value})
}
handleSubmit = (e) => {
console.log(e)
e.preventDefault()
}
createFormGroup(i) {
const title = i[0],
placeholder = i[1],
type = i[2]
const titleCamelCase = camelize(title);
if (type === "file") {
return (
<>
<label key={titleCamelCase + "-label"} htmlFor={titleCamelCase}>
Player Profile Image
</label>
<InputGroup key={titleCamelCase + "-group"} mb="3">
<Form.CustomFile
required
onChange={this.handleFileInputChange}
key={titleCamelCase + "-file"}
id={titleCamelCase}
accept=".jpg, .jpeg, .png"
>
{this.state.profileImageFilename
? this.state.profileImageFilename
: "Choose an image. ( .jpg, .jpeg, .png, .gif )"}
</Form.CustomFile>
</InputGroup>
</>
);
}
return (
<>
<label key={titleCamelCase + "-label"} htmlFor={titleCamelCase}>
{title}
</label>
<Form.Input
key={titleCamelCase + "-input"}
mb="3"
required
type={type}
id={titleCamelCase}
placeholder={placeholder}
onChange={this.handleInputChange}
valule={this.state[titleCamelCase]}
/>
</>
);
}
render() {
return (
<Layout>
<Form onSubmit={this.handleSubmit}>
<Form.Group>
{/* {formContent.map(function(i){this.createFormGroup(i)}.bind(this))} */}
{formContent.map((i)=>this.createFormGroup(i))}
</Form.Group>
<Button primary type="submit">
Submit
</Button>
</Form>
</Layout>
);
}
}
export default ProfileForm
问题
class 组件的 this
未绑定到 handleFileInputchange
回调处理程序。
解决方案
您应该在 constructor
中将 this
绑定到 handleFileInputchange
或将其声明为箭头函数。
constructor(props) {
super(props);
this.state = {
profileName: '',
playerName: '',
profileImageFilename: '',
};
this.handleFileInputchange = this.handleFileInputchange.bind(this);
}
或
handleFileInputchange = (e) => {
console.log(e);
this.setState({ profileImageFilename: e.target.file[0].filename });
}
您还可以安全地删除匿名回调并直接传递 this.handleFileInputChange
,因为 onChange
事件处理程序和您的回调具有相同的函数签名:
onChange={this.handleFileInputChange}
更新
我用你的代码创建了一个 codesandbox。奇怪的是,我也没有看到任何 onChange 回调触发(控制台日志),我什至添加了一个 componentDidUpdate
来记录状态更新,这也没有触发。我可以添加一个新文件并看到带有我选择的文件名的文本工具提示,但 UI 中没有任何更新。如果您的 bootstrap 输入仍然导致问题,我建议实施原始输入元素。
@drew 我最终不得不使用 标准输入 元素,因为我找不到任何证据表明反应 bootstrap 组件触发了更改事件。谢谢您的意见。您可能需要修改您的答案,因为正确的部分已在您的评论中。