出现奇异的 Cannot red property addEventListener of null

#1

问题出现在(已确认)

<a href="#" onClick={this.viewConfigFile.bind(this, file.url, file.path)}>
  {file.path}
</a>

就是这个onClick事件找不到 viewConfigFile这个事件,报错 Cannot red property ‘addEventListener’ of null。
可问题是页面加载后,点击这个超链接是可以运行这个viewConfigFile的。那么,本人就猜想是 compoentWillReceiveProps更新页面的原理的问题。
在网上已经看过相关blog,可还是解释不出为什么会出现这个错误,求大神指导一二。


先简述页面的加载逻辑:
@1. 首先,ConfigFileListView这个组件加载时,会去后台申请加载文件数据。假设一开始,是请求url为’/stats/admin/configlist’的后台数据。
@2. 之后,由于父组件触发动作将redux的store中 state.router.location.pathnamem更改为‘/stats/admin/generatedconfiglist’。此时,store会通知ConfigFileListView的urlPath发了了变化,此时会将更新props,从而触发compoentWillReceiveProps。就在这时,浏览器打印出了错误 ‘addEventListener’ of null‘’ 。其他显示和操作一切正常,包括这个viewConfigFile事件也可以正常工作。


以上是,问题描述,下面给出代码:

import React from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {getRouteKeyword} from '../../utils/SmallUtil';
import {getTscFileData, resetTscData, baseFetchDataForGet, resetDataInState} from '../../actions/configFile';
import {Table, Panel, Pagination, Modal, Button, PanelGroup} from 'react-bootstrap';
import {getShowItems} from '../../utils/SmallUtil';


// this component is for the "Uploaded Config File List" and "Generated Config File List" features
// of the column:"Config Files"
export class ConfigFileListView extends React.Component {

   constructor(props) {
       super(props);

       this.state = {
           activePage: 1,
           showModal: false,
           fileName: null,
           activePanel: 0
       };
   }

   componentWillMount() {
       this.fetchData();
   }

   componentWillReceiveProps(nextProps) {
       if(nextProps.urlPath != this.props.urlPath)
           this.fetchData();
   }

   fetchData() {
       let token = this.props.token;
       let secret = this.props.secret;
       let url = '';
       let urlPath = this.props.urlPath;
       if (urlPath == '/admin/config-files/uploaded') { //uploaded
           url = '/stats/admin/configlist';
       } else { //generated
           url = '/stats/admin/generatedconfiglist';
       }

       this.props.baseFetchDataForGet(token, secret, url);
   }

   viewConfigFile(url, fileName) {
       let token = this.props.token;
       let secret = this.props.secret;

       this.state.fileName = fileName;
       this.props.getTscFileData(token, secret, url);
   }


   componentWillUnmount() {
       this.props.resetDataInState();
   }

   render() {
       let data = null;
       if (this.props.data)
           data = this.props.data.folders;

       let folders = null;
       if (data)
           folders = getShowItems(data, 9, this.state.activePage);//show 9 items on one page;

       let rightTitleName;
       let currentUrl = this.props.urlPath;//"/admin/config-files/generated"
       let viewChoice = getRouteKeyword(currentUrl);
       if (viewChoice == 'uploaded') { //uploaded
           rightTitleName = 'Config File List: Uploaded';
       } else { //generated
           rightTitleName = 'Config File List: Generated';
       }

       let sTscContent = this.props.sTscData;
       if (sTscContent !== null) {
           this.state.showModal = true;
       }

       return (
           <div className="col-md-10">
               <Panel header={rightTitleName} className="panel-success">
                   {
                       this.props.isFetching === true || folders ===null ? <h3>Loading data...</h3> :
                           <div>
                               <Pagination
                                   ellipsis
                                   boundaryLinks
                                   bsSize="medium"
                                   items={Math.ceil(data.length/9)}
                                   maxButtons={8}
                                   activePage={this.state.activePage}
                                   onSelect={this.handlePageSelect.bind(this)} />

                               <PanelGroup activeKey={this.state.activePanel} onSelect={this.handlePanelSelect.bind(this)} accordion>
                                   {
                                       folders === undefined || folders.length === 0 ? '' : folders.map((folder, index1 = 0) =>
                                           <Panel key={index1} eventKey={index1} collapsible header={<h3>{folder.name}</h3>} bsStyle="success">
                                               <Table striped bordered condensed hover responsive>
                                                   <thead>
                                                   <tr>
                                                       <th>File Name</th>
                                                       <th>Related Products</th>
                                                       <th>Operation</th>
                                                   </tr>
                                                   </thead>
                                                   <tbody>
                                                   {
                                                       folder.files.length == 0 ? '' : folder.files.map((file, index2 = 0) =>
                                                           <tr key={index2}>
                                                               <td>
                                                                   <a href="#" onClick={this.viewConfigFile.bind(this, file.url, file.path)}>
                                                                       {file.path}
                                                                   </a>
                                                               </td>
                                                               <td>
                                                                   <p>
                                                                       {
                                                                           file.relations.length == 0 ? <a>N/A</a> :
                                                                               file.relations.map((relation, index3 = 0) =>
                                                                                   <a key={index3}>{' ' + relation.product + ' , '}</a>
                                                                           )
                                                                       }
                                                                   </p>
                                                               </td>
                                                               <td>coming soon</td>
                                                           </tr>
                                                       )
                                                   }
                                                   </tbody>
                                               </Table>
                                           </Panel>
                                       )
                                   }
                               </PanelGroup>
                           </div>
                   }
       );
   }
   }


const mapStateToProps = (state) => ({
   data: state.configfile.data,
   isFetching: state.configfile.isFetching,
   sTscData: state.configfile.sTscData,
   token: state.auth.token,
   secret: state.auth.secret,
   urlPath: state.router.location.pathname
   });


function mapDispatchToProps(dispatch) {
   return bindActionCreators({
       baseFetchDataForGet,
       resetDataInState
   }, dispatch);
   }


export default connect(mapStateToProps, mapDispatchToProps)(ConfigFileListView);
#2

代码都压在一起了,建议修改下。
然后debugger的问题,建议去除业务逻辑,精简代码,还原到demo级别的时候,debugger速度会快点。