【问题标题】:Why I getting an error that says `table is null` although I can see the data in the table?尽管我可以看到表中的数据,但为什么我得到一个错误,说“表为空”?
【发布时间】:2017-10-31 22:45:08
【问题描述】:

我正在将一些数据加载到我的React 组件中的table 中。我正在使用来自materialize CSS framework 的表格显示数据。我可以看到表格中的数据。我正在使用来自 W3school.com 的table sort function。当我单击header 调用sortTable function 时,我收到一个错误消息TypeError: Table is null。产生错误的行是rows = table.getElementsByTagName('TR');。尽管我可以看到表格中的数据,但我不明白为什么会出现此错误?我的代码如下所示:

import React, { Component } from 'react';

class newsList extends Component {
    constructor(props) {
        super(props)
        window.info = [];
    }

    render() {
        this.props.arr.result ? window.info.push(this.props.arr.result) : null

        var result = window.info.map(item => (
            <tbody key={item.id}>
                <tr>
                    <td>{item.profileInfo.profileName}</td>
                    <td>{item.rows[0][0]}</td>
                    <td>{item.rows[0][1]}</td>
                    <td>{item.rows[0][2]}</td>
                    <td>
                        <a href="#!" className="secondary-content">
                            <i className="material-icons">
                                send
                        </i>
                        </a>
                    </td>
                </tr>
            </tbody>))

        //Sort function starts here.
        const sortTable = (n) => {
            console.log(window.info);
            var table, rows, switching, i, x, y, shouldSwitch, dir, switchCount = 0;
            table = document.getElementById('#dataTable');
            console.log(table);
            switching = true;

            //Sort the sorting direction to ascending:
            dir = 'asc';

            //Make a loop that will continue until no switching has been done:
            while (switching) {

                //Start by saying: no switching is done:
                switching = false;

                rows = table.getElementsByTagName('TR');

                //Loop through all table rows except the headers:
                for (i = 1; i < (rows.length - 1); i++) {

                    //Start by saying there should be no switching:
                    shouldSwitch = false;

                    //Compare the two elements:
                    x = rows[i].getElementsByTagName('TD')[n];
                    y = rows[i].getElementsByTagName('TD')[n];

                    //Switch the rows:
                    if (dir === 'asc') {
                        if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
                            shouldSwitch = true;
                            break;
                        }
                    } else if (dir === 'desc') {
                        if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
                            shouldSwitch = true;
                            break;
                        }
                    }
                }
                if (shouldSwitch) {
                    //If a switch has been done marked, make the switch and mark that a  switch has been done:
                    rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
                    switching = true;

                    //Each time a switch is done, increase this count by 1:
                    switchCount++;
                } else {
                    //If no Switching has been done AND the direction is 'asc' set the direction to 'desc' and run the while loop again.
                    if (switchCount === 0 && dir === 'asc') {
                        dir = 'desc';
                        switching = true;
                    }
                }
            }
        }

        return (
            <div>
                <table id="dataTable" className="responsive-table">
                    <thead>
                        <tr>
                            <th onClick={() => sortTable(0)}>Account Name</th>
                            <th>Sessions</th>
                            <th>Bounces</th>
                            <th>Users</th>
                        </tr>
                    </thead>
                    {result}
                </table>
            </div>
        )
    }
}

export default newsList;

【问题讨论】:

  • table 为空,因为document.getElementId 不需要# 符号来表示您正在寻找一个ID,它已经知道它是由于您使用的方法,只是寻找document.getElementById('dataTable')。也就是说,将 React 与 DOM 操作混合是一个糟糕的主意
  • @Icepickle 是的,我知道这是一个糟糕的主意,但我很难理解 React 文档中的 setState,而且我不知道其他方法。
  • 那你真的应该回到基础,因为你在这里做的事情将来会让你很头疼。如果只是对您需要的表格进行排序,这不是什么大问题,请不要继续在这里拼凑的内容

标签: javascript reactjs sorting


【解决方案1】:

因此,正如评论中所回答的,您收到的错误是因为您使用 document.getElementById 方法来获取您的表格,但您包含井号 (#) 符号,这不是 document.getElementById 所必需的函数需要一个与 id 完全匹配的参数,所以理论上应该是 dataTable,仅此而已;)

现在,我确实在理论上说,这是有充分理由的,即您似乎在使用 React,并且将它与 DOM 操作混合在一起。将这两者混合起来简直是个坏主意,因为 React 与虚拟 DOM 一起工作,一旦状态发生变化,它就会重新渲染你的数据。但是,当您开始修改 DOM 时,它不会收到通知,因此可能会发生一些有趣的事情。

有一点是肯定的,您的排序方法可能永远不会按预期工作,老实说,我不想成为在这种情况下必须调试问题所在的人。

那么让我们来看看你的代码吧:

constructor(props) {
    super(props)
    window.info = [];
}

这已经是一个非常有趣的开始了,这告诉我这个组件只能使用一次,因为它似乎将事物与全局变量混合在一起,虽然我不知道你为什么要这样做,我可以告诉你现在已经,你真的不应该。最多在构造函数中你会发现一些initial state 的设置,也许是this 的一些方法绑定,但仅此而已,不要通过构造函数操作全局对象!

render() {
    this.props.arr.result ? window.info.push(this.props.arr.result) : null

这让它变得更有趣了,你通过 props 接收了一些数组,你似乎想把它们推到我们之前看到的那个全局对象中,原因真的超出了我的想象,如果它不存在,我们是null。这样的代码行至少应该解释为什么,但最好不要在那里,因为它们没有意义

var result = window.info.map(item => (
    <tbody key={item.id}>

好的,您在此处映射,并创建结果集以供以后使用。应该注意的是,使用this.props.arr.result 进行映射会更有意义,而不是使用那个有趣的全局变量...

//Sort function starts here.
const sortTable = (n) => {

这个方法很好,你的错误来自哪里,但是请删除它,绝对没有理由使用这种排序算法,并且不要在改变状态或道具之外操作 DOM,使用存储或减速器.这个方法真的不应该在这里。我也不想用这个方法研究更深的细节,虽然它是那里最好的注释代码,但应该删除它

return (
    <div>
        <table id="dataTable" className="responsive-table">
            <thead>
                <tr>
                    <th onClick={() => sortTable(0)}>Account Name</th>
                    <th>Sessions</th>
                    <th>Bounces</th>
                    <th>Users</th>
                </tr>
            </thead>
            {result}
        </table>
    </div>
)

这段代码似乎是 React :) 一个主要的批评点是 table 上的 id 属性,它在 React 应用程序中没有位置。如果您想让您的表格在内部可调用,您可以使用ref=((e) =&gt; this.table = e 回调,这样您就可以在内部与您希望跟踪的元素对话。

请注意,我不仅想为您提供有关您正在使用的技术的信息,不,我还想为您提供另一种处理排序、状态和表格的方式,以更 React 的方式,所以请随意通过以下代码工作。它显示了我最喜欢的比利时球队目前在冠军联赛中的表现有多么糟糕,所以我忽略了分数;)

它有 2 个表示组件(TableHeader、TableRow)和 1 个容器组件(Table),可能/应该更多,但我很感兴趣的是向您展示如何使用初始状态和管理排序(虽然基本上只是处理)

const TableHeader = ({ columns, onClick, activeColname, isDescending }) => {
  
  return <thead>
    { columns.map( (col, key) => <th className={activeColname === col.name ? 'sort ' + (isDescending ? 'descending': 'ascending') : ''} key={`header${key}`} onClick={() => onClick( col )}>{col.title}</th> ) }
  </thead>;
};

const TableRow = ({ row, columns }) => {
  return <tr>
    { columns.map( (col, key) => <td key={`cell${key}`}>{ row[col.name] }</td> ) }
  </tr>;
};

class Table extends React.Component {
  constructor() {
    super();
    this.state = {
      order: null
    };
  }
  columnClicked( column ) {
    console.log('got clicked ', column);
    let { order } = this.state;
    this.setState({
      order: {
        name: column.name,
        descending: order && order.name === column.name && !order.descending
      }
    });
  }
  render() {
    let { columns, rows } = this.props;
    let { order } = this.state;
    if (order) {
      // sort, if necessary
      let { name, descending } = order;
      console.log(`ordering by ${name} in ${descending}`);
      rows = [...rows].sort( (a, b) => (a[name] > b[name] ? 1 : -1) * (descending ? -1 : 1) );
    }
    return <table>
      <TableHeader columns={columns} activeColname={order && order.name} isDescending={order && order.descending} onClick={(...args) => this.columnClicked(...args)} />
      <tbody>
      { rows.map( (row, key) => <TableRow row={row} columns={columns} key={row.id} /> ) }
      </tbody>
      </table>;
  }
};

const columns = [
  { title: 'Team', name: 'team' },
  { title: 'Played', name: 'played' },
  { title: 'Won', name: 'won' },
  { title: 'Equal', name: 'equal' },
  { title: 'Lost', name: 'lost' }
];

const data = [
  { id: 0, team: 'PSG', played: 4, won: 4, equal: 0, lost: 0 },
  { id: 1, team: 'Bayern munchen', played: 4, won: 3, equal: 0, lost: 1 },
  { id: 2, team: 'Celtic Glasgow', played: 4, won: 1, equal: 0, lost: 3 },
  { id: 3, team: 'RSCA Anderlecht', played: 4, won: 0, equal: 0, lost: 4 }
];

ReactDOM.render( <Table columns={columns} rows={data} />, document.querySelector('#app') );
.sort {
  text-decoration: underline;
}
.ascending::after {
  content: '▲';
}
.descending::after {
  content: '▼';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

我添加了一些指向React documentation 的链接,我真的希望您花一些时间阅读它们;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多