React 中的动态表单,无法读取未定义的属性“地图”
Posted
技术标签:
【中文标题】React 中的动态表单,无法读取未定义的属性“地图”【英文标题】:Dynamic Forms in React, Cannot read property 'map' of undefined 【发布时间】:2020-05-27 04:17:07 【问题描述】:概述
所以我只是 React 的新手,我在尝试创建动态表单时遇到了麻烦。目前我希望 bug.pages 和 bug.steps_to_reproduce 是动态的,这意味着当我单击“+ 添加页面”之类的按钮时,它会将新字段添加到 bug.pages 并在表单上显示新字段。
问题
当我向渲染方法添加多个 const 时,当我输入其中一个页面或 steps_to_reproduce 字段 (onChange) 时,它会吐出一个错误 (TypeError: Cannot read property 'map' of undefined
)。错误总是指向第一个 const,如果我删除其中一个 const,它会按预期工作。
我的尝试
因此,“bugSteps”和“bugPages”const 函数与“onChange”函数中的相应 if 语句几乎重复。如果我删除对“bugSteps”或“bugPages”的所有引用,表单会按预期工作,但似乎无法找到为什么会同时抛出错误。
代码
import React, Component from 'react';
import PropTypes from 'prop-types';
import connect from 'react-redux';
import createNewTicket from '../../actions/ticket.action';
class NewerTicketForm extends Component
constructor(props)
super(props);
this.state =
name: '',
type: 'Bug',
status: 'Open',
priority: 'Low',
summary: '',
bug:
pages: [
text: '',
url: ''
],
page_sections: [],
steps_to_reproduce: [
step: '',
order: 0
],
expected_result: '',
actual_result: '',
attachments: []
,
improvement:
pages: [
text: '',
url: ''
],
page_sections: [
text: '',
url: ''
],
current_situation: '',
improved_requirements: '',
improved_requirements_attachments: [],
attachments: []
,
new_feature:
requirements: [],
requirements_attachments: [
type: '',
filename: '',
url: ''
]
,
comments: [],
changes: [],
submitted_by: '',
assigned_to: '',
project: '',
expected_close_date: ''
;
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.addPage = this.addPage.bind(this);
onChange(e)
console.log(e.target.name);
if (['text', 'url'].some(str => e.target.name.includes(str)))
console.log('A');
let field = e.target.name.split('-');
console.log(field);
let bugPages = [...this.state.bug.pages];
bugPages[parseInt(field[1])][field[0]] = e.target.value;
console.log(bugPages);
this.setState(
bug:
pages: bugPages
);
else if (['step', 'order'].some(str => e.target.name.includes(str)))
console.log('B');
let field = e.target.name.split('-');
console.log(field);
let bugSteps = [...this.state.bug.steps_to_reproduce];
bugSteps[parseInt(field[1])][field[0]] = e.target.value;
console.log(bugSteps);
this.setState(
bug:
steps_to_reproduce: bugSteps
);
else
console.log('C');
this.setState( [e.target.name]: e.target.value )
onSubmit(e)
e.preventDefault();
const ticketInfo =
name: this.state.name,
type: this.state.type,
status: this.state.status,
priority: this.state.priority,
summary: this.state.summary,
submitted_by: this.props.user,
project: this.props.project,
expected_close_date: this.state.expected_close_date
;
this.props.createNewTicket(ticketInfo)
.then(res => alert('success'))
.catch(res => alert('failed'));
addPage(e)
let pages = this.state.bug.pages;
pages.push(
text: '',
url: ''
);
this.setState(bug:
pages: pages
);
render()
const bugSteps = this.state.bug.steps_to_reproduce.map((val, idx) =>
let stepId = `step-$idx`;
let key = `bug-steps-$idx`;
return (
<div key=key>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Step idx: </label>
</div>
<div className="col-10">
<input type="text" className="form-control" name=stepId value=val.step onChange=this.onChange />
</div>
</div>
</div>
);
);
const bugPages = this.state.bug.pages.map((val, idx) =>
let textId = `text-$idx`;
let urlId = `url-$idx`;
let key = `bug-page-$idx`;
return (
<div key=key>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Page Name: </label>
</div>
<div className="col-10">
<textarea className="form-control" name=textId rows="3" value=val.text onChange=this.onChange></textarea>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Page Url: </label>
</div>
<div className="col-10">
<input type="text" className="form-control" name=urlId value=val.url onChange=this.onChange />
</div>
</div>
</div>
);
);
return (
<div className="row">
<div className="col-12 text-center">
<h2>Create New Ticket</h2>
</div>
<div className="col-12 ">
<form onSubmit=this.onSubmit>
<div className="form-group row">
<div className="col-2 text-center">
<label>Ticket Name: </label>
</div>
<div className="col-10 text-center">
<input type="text" className="form-control" name="name" required value=this.state.name onChange=this.onChange />
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Type: </label>
</div>
<div className="col-10">
<select className="form-control" name="type" required onChange=this.onChange>
<option value="Bug" selected>Bug</option>
<option value="Improvement">Improvement</option>
<option value="New Feature">New Feature</option>
</select>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Status: </label>
</div>
<div className="col-10">
<select className="form-control" name="status" required onChange=this.onChange>
<option value="Open" selected>Open</option>
<option value="In Progress">In Progress</option>
<option value="Awaiting SignOff">Awaiting SignOff</option>
</select>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Priority: </label>
</div>
<div className="col-10">
<select className="form-control" name="status" required onChange=this.onChange>
<option value="Low" selected>Low</option>
<option value="Medium">Medium</option>
<option value="High">High</option>
<option value="Critical">Critical</option>
</select>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Summary: </label>
</div>
<div className="col-10">
<textarea className="form-control" name="summary" rows="3" value=this.state.summary onChange=this.onChange></textarea>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Expected Close Date: </label>
</div>
<div className="col-10">
<input type="date" className="form-control" name="expected_close_date" value=this.state.expected_close_date onChange=this.onChange />
</div>
</div>
this.state.type === 'Bug' &&
<div>
<div className="row">
<div className="col-12 text-center">
<hr />
<h3><small>Bug Details</small></h3>
</div>
</div>
bugPages
<div className="row mb-4">
<div className="col-12 text-center">
<button type="button" className="btn btn-success" onClick=this.addPage>+ Add Page</button>
</div>
</div>
bugSteps
<div className="form-group row text-center">
<div className="col-12 ">
<label>Steps to Reproduce: </label>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Expected Results: </label>
</div>
<div className="col-10">
<textarea className="form-control" name="text" rows="3" value=this.state.bug.expected_result onChange=this.onChange></textarea>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Actual Results: </label>
</div>
<div className="col-10">
<textarea className="form-control" name="text" rows="3" value=this.state.bug.actual_result onChange=this.onChange></textarea>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Attachements: </label>
</div>
<div className="col-10">
<input type="file" className="form-control-file" name="url" />
</div>
</div>
</div>
this.state.type === 'Improvement' &&
<div>
<div className="row">
<div className="col-12 text-center">
<hr />
<h3><small>Improvement Details</small></h3>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Page Name: </label>
</div>
<div className="col-10">
<textarea className="form-control" name="text" rows="3" value=this.state.improvement.pages[0].text onChange=this.onChange></textarea>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Page Url: </label>
</div>
<div className="col-10">
<input type="text" className="form-control" name="url" value=this.state.improvement.pages[0].url onChange=this.onChange />
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Page Section: </label>
</div>
<div className="col-10">
<textarea className="form-control" name="text" rows="3" value=this.state.improvement.pages[0].text onChange=this.onChange></textarea>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Page Section Url: </label>
</div>
<div className="col-10">
<input type="text" className="form-control" name="url" value=this.state.improvement.pages[0].url onChange=this.onChange />
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Current Situation: </label>
</div>
<div className="col-10">
<textarea className="form-control" name="current_situation" rows="3" value=this.state.improvement.current_situation onChange=this.onChange></textarea>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Requirements: </label>
</div>
<div className="col-10">
<textarea className="form-control" name="improved_requirements" rows="3" value=this.state.improvement.improved_requirements onChange=this.onChange></textarea>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Attachements: </label>
</div>
<div className="col-10">
<input type="file" className="form-control-file" name="url" />
</div>
</div>
</div>
this.state.type === 'New Feature' &&
<div>
<div className="row">
<div className="col-12 text-center">
<hr />
<h3><small>New Feature Details</small></h3>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Requirements: </label>
</div>
<div className="col-10">
<textarea className="form-control" name="requirements" rows="6" value=this.state.new_feature.requirements onChange=this.onChange></textarea>
</div>
</div>
<div className="form-group row text-center">
<div className="col-2 ">
<label>Attachements: </label>
</div>
<div className="col-10">
<input type="file" className="form-control-file" name="url" value=this.state.new_feature.requirements_attachments[0].url onChange=this.onChange />
</div>
</div>
</div>
<div className="row">
<div className="col-12 text-center">
<button type="submit" className="btn btn-primary">Create Ticket</button>
</div>
</div>
</form>
</div>
</div>
);
NewerTicketForm.propTypes =
createNewTicket: PropTypes.func.isRequired
;
const mapStateToProps = state => (
company: state.company.currentCompany,
project: state.project.currentProject,
user: state.loggedInUser.user
);
export default connect(mapStateToProps, createNewTicket )(NewerTicketForm);
任何帮助或第二双眼睛将不胜感激。
【问题讨论】:
提供最少的代码。 【参考方案1】:当您更新“错误”状态时,您可能会丢失之前设置的信息。你可以试试:
this.setState((prevState) =>
bug:
...prevState.bug,
pages: bugPages
);
和
this.setState((prevState) =>
bug:
...prevState.bug,
steps_to_reproduce: bugSteps
);
如果您在使用对象之前对其进行测试,也有助于防止错误,例如
let bugSteps;
if (this.state.bug && this.state.bug.steps_to_reproduce && this.state.bug.steps_to_reproduce.length)
bugSteps = this.state.bug.steps_to_reproduce.map((val, idx) =>
...
【讨论】:
这个问题/答案可能会有所帮助:***.com/questions/24898012/… 这对你有用还是你还有问题?以上是关于React 中的动态表单,无法读取未定义的属性“地图”的主要内容,如果未能解决你的问题,请参考以下文章
如何在 React with Jest 和 Enzyme 中测试表单提交?无法读取未定义的属性“preventDefault”