为什么我得到一个错误,表示`table is null`虽然我可以看到表中的数据?

时间:2017-10-31 22:45:09

标签: javascript reactjs sorting

我正在将一些数据加载到table组件中的React。我正在使用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;

1 个答案:

答案 0 :(得分:1)

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

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

有一件事是肯定的,你的排序方法可能永远不会按预期工作,说实话,我不想成为那些必须调试在这种情况下出错的人。

让我们稍微讨论你的代码:

dataTable

这已经是一个非常有趣的开始,这告诉我这个组件可以使用一次,因为它似乎与全局变量混合,虽然我不知道为什么你想这样做,我可以告诉你现在已经,你真的不应该。最多,在构造函数中你会发现一些initial state设置,也许是与constructor(props) { super(props) window.info = []; } 的一些方法绑定,但就是这样,不要通过构造函数来操纵全局对象!

this

这让它变得更有趣,你通过道具接收了一些数组,而你似乎想把它们推到我们之前看到的那个全局对象中,原因超出了我的想象,如果它不存在,我们是render() { this.props.arr.result ? window.info.push(this.props.arr.result) : null 。这样的代码行至少应该对原因进行评论,但最好不应该在那里,因为它们没有意义

null

好,你在这里映射,并创建结果集供以后使用。应该注意的是,用var result = window.info.map(item => ( <tbody key={item.id}> 映射更有意义,而不是用那个有趣的全局变量...

this.props.arr.result

这个方法很好,你的错误来自,但请删除它,绝对没有理由使用这样的排序算法,并且不要在改变状态或道具之外操纵DOM,与商店或者减少器一起使用。这个方法真的不应该在这里。我也不想用这种方法深入研究,虽然它是那里最好的注释代码,但它应该被删除

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

这段代码似乎是React :)批评的一个主要观点是表上的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应用程序中没有位置。如果你想让你的表在内部可调用,你可以使用ref=((e) => this.table = e回调,这样你就可以在内部与你想要跟踪的元素进行对话。

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

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

id
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: '▼';
}

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