开发者问题收集

在浏览器中加载 html 页面时出现“未捕获的类型错误:无法读取未定义的属性‘map’”

2018-03-15
419

我使用 react js 编写了部分代码来开发网站。

加载 localhost/events.html 页面时,我发现网页中缺少事件类数据。

只有在浏览同一网站的不同页面后,我才能在 events.html 中看到事件类数据。但第一次访问该页面时看不到。

以下是在 chrome 开发人员工具中找到的堆栈跟踪。我在其他浏览器上也遇到了同样的问题。

Uncaught TypeError: Cannot read property 'map' of undefined
at EventClasses.render (Events.js:24)
at ReactCompositeComponent.js:793
at measureLifeCyclePerf (ReactCompositeComponent.js:73)
at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (ReactCompositeComponent.js:792)
at ReactCompositeComponentWrapper._renderValidatedComponent (ReactCompositeComponent.js:819)
at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:359)
at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:255)
at Object.mountComponent (ReactReconciler.js:43)
at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:368)
at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:255

相应 Events.js 文件的代码

import React, {PureComponent} from 'react';
import marked from 'marked'
import {createStructuredSelector} from 'reselect';
import {connect} from 'react-redux';
import $ from 'jquery'
import moment from 'moment'
import {analytics} from '../../../utils/trackingHelpers';
import {load_contentful} from '../actions';
import {selectEventClasses} from '../selectors';

export class EventClasses extends PureComponent {

    componentDidMount(){
        const {dispatch, load_contentful} = this.props;
        dispatch(load_contentful());
    }

    render(){
        const {events} = this.props;
        //Setting values in nextClass field
        events.map((e) => {
            e.nextClass = {};
            var sDate = new Date(e.startTime);
            e.startDateTime = sDate;
            var options = {weekday: 'short', year: 'numeric', month: 'long', day: 'numeric'};
            var sDateStr = sDate.toLocaleDateString('en-US', options);
            e.nextClass.day = sDateStr.split(', ')[0];

            var dateOptions = {year: 'numeric', month: 'long', day: 'numeric'};
            e.nextClass.date = sDate.toLocaleDateString('en-US', dateOptions);

            var eDate = new Date(e.endTime);
            var dayOptions = {year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', hc: 'h12'};
            var startTime = sDate.toLocaleDateString('en-US', dayOptions);
            var endTime = eDate.toLocaleDateString('en-US', dayOptions);


            var startTimeArr = startTime.split(' ');
            var endTimeArr = endTime.split(' ');
            var startTimeStr = startTimeArr[3].length==4?'0'+startTimeArr[3]:startTimeArr[3];
            var endTimeStr = endTimeArr[3].length==4?'0'+endTimeArr[3]:endTimeArr[3];
            e.nextClass.time = startTimeStr+' '+startTimeArr[4]+' - '+endTimeStr+' '+endTimeArr[4]; 
            e.nextClass.location = e.location; 
            return e;
        });
        //Sorting the events array in ascending order of startDateTime
        var key = 'startDateTime';
        events.sort(function(a, b) {
            var x = a[key] == null? "":a[key]; 
            var y = b[key] == null? "":b[key]; 
            return x < y ? -1 : x > y ? 1 : 0;
        });

        return <div>
        {events.map((event, index) =>
            <div key={`events${index}`} className="event">
                    <div className="event-inner">
                        <div className="event-details">
                            <h2 className={`event-title title-icon-${event.icon}`}>
                                {event.title}
                            </h2>
                            <div className="event-meta">
                                <ul>
                                    <li>Introductory Fee: ${event.fee}</li>
                                    <li>Location: {event.location}</li>
                                    <li>Instructor: {event.instructor}</li>
                                </ul>
                                {event.allClasses ? <a className="event-all-dates">See All Class Dates</a> : null}
                            </div>
                            <div className="event-description" dangerouslySetInnerHTML={{__html: marked(event.description)}}/>
                        </div>
                        <div className="event-other">
                            <div className="event-other-inner">
                                <div className="event-next-class">
                                    <div className="event-next-class-inner">
                                        <h2 className="event-next-class-title">Info</h2>
                                        <div className="event-next-class-description">
                                            <ul>
                                                <li>{event.nextClass.day} | {event.nextClass.date}</li>
                                                <li>{event.nextClass.time}</li>
                                                <li>Location: {event.nextClass.location}</li>
                                            </ul>
                                        </div>
                                    </div>
                                </div>
                                <div className="event-cta">
                                    <a href={event.link} target="_blank" onClick={() => analytics('event', `Classes:click:Book This Class (${event.title} - ${event.nextClass.date}) CTA`)} className="btn btn__secondary btn__lg btn__uppercase event-cta-btn">Book This Class</a>
                                </div>
                            </div>
                        </div>
                    </div>
            </div>)
        }
        </div>
    }
}

//export default Events;

const mapStateToProps = createStructuredSelector({
    events: selectEventClasses()
});

function mapDispatchToProps(dispatch) {
    return {
        dispatch,
        load_contentful
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(EventClasses);
2个回答

尝试设置默认道具

EventClasses.defaultProps = {
    events: []
}
Wilson Liao
2018-03-16
  1. 您必须将状态传递给选择器。
  2. 您可以检查事件是否已定义,这样您就不会在未定义的情况下进行映射。
  3. 避免在渲染时进行所有这些计算。渲染应该渲染组件,而不是进行所有这些计算。
giggi__
2018-03-15