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”

无法使用React redux读取未定义的地图属性

无法读取 React 中未定义的属性“映射”

TypeError:无法读取未定义的 React 类组件的属性“onMouse”

无法读取未定义的属性'$ valid'

使用带有formik的react-select时无法读取未定义的属性“类型”