ReactJS:onClick()排序动态呈现的元素

时间:2017-12-08 13:23:52

标签: javascript reactjs onclick addeventlistener

我正在将从API获取的数据打印到表中,我在按字母顺序和数字顺序对列值进行排序时遇到一些困难。如果API中的列数据包含数值,即 10.01, 333.01, 8.99 or 100.88 等,则可以在首次点击时从 0 -> 100 进行升序排序第二次点击降序 100 -> 0 ,并按字母顺序排列相同的逻辑,即 a-z && Z-A ,反之亦然。

我熟悉的功能 onclick="sortTable(0)" ,在React中的功能不一样,就像我以前用javaScript编写代码一样。可能我误导了ES6标准,但我不确定。

Here is how it's look like my table without sorting functionality.

以下是我的代码示例 onclick="sortTable(0)" ,但它不能很好地运作:

class App extends React.Component
{
    constructor()
    {
        super();
        this.state = {
            rows: [],
            columns: [],
            clicked: false
        }

        this.handleClick = this.handleClick.bind( this );
    }

    handleClick()
    {
        this.setState( {
            clicked: true
        } );
    }


     sortTable( n )
{
            var table, columns, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
            table = document.getElementById( "datagrid" );
            switching = true;
            //Set 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;
                columns = table.getElementsByTagName( "TH" );
                /*Loop through all table rows (except the
                first, which contains table headers):*/
                for ( i = 1; i < ( columns.length - 1 ); i++ )
                {
                    //start by saying there should be no switching:
                    shouldSwitch = false;
                    /*Get the two elements you want to compare,
                    one from current row and one from the next:*/
                    x = columns[i].getElementsByTagName( "TH" )[n];
                    y = columns[i + 1].getElementsByTagName( "TH" )[n];
                    /*check if the two rows should switch place,
                    based on the direction, asc or desc:*/
                    if ( dir == "asc" )
                    {
                        if ( x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase() )
                        {
                            //if so, mark as a switch and break the loop:
                            shouldSwitch = true;
                            break;
                        }
                    } else if ( dir == "desc" )
                    {
                        if ( x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase() )
                        {
                            //if so, mark as a switch and break the loop:
                            shouldSwitch = true;
                            break;
                        }
                    }
                }
                if ( shouldSwitch )
                {
                    /*If a switch has been 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;
                    }
                }
            }
        }

    componentDidMount()
    {

        fetch( "http://ickata.net/sag/api/staff/bonuses/" )
            .then( function ( response )
            {
                return response.json();
            } )
            .then( data =>
            {
                this.setState( { rows: data.rows, columns: data.columns } );
            } );

    }

    render()
    {

        return (
            <div id="container" className="container">
                <h1>Final Table with React JS</h1>
                <table className="datagrid">
                    <thead>
                        <tr> {
                            this.state.columns.map(( column, index ) =>
                            {
                                return ( <th onClick={this.handleClick}>{column}</th> )
                            }
                            )
                        }
                        </tr>
                    </thead>
                    <tbody> {
                        this.state.rows.map( row => (
                            <tr>{row.map( cell => (
                                <td>{typeof cell === 'number' ? cell.toFixed( 2 ) : cell}</td>
                            ) )}
                            </tr>
                        ) )
                    }
                    </tbody>
                </table>
            </div>
        )
    }
}


ReactDOM.render( <div id="container"><App /></div>, document.querySelector( 'body' ) );

欢迎您直接参与我的回购:Fetching API data into a table

我的示例,在使用 onclick="sortTable(0)" 之后,并未在控制台中显示任何错误,但它会打印相同的结果。我想我没有正确处理 <th onClick={this.handleClick}>{column}</th> 元素。

onClick event doesn't dunction

很遗憾,我无法在ReactJs.org

找到相关文档

根本没有onClick事件的功能,因此我无法调试sor功能。

任何建议将不胜感激!

2 个答案:

答案 0 :(得分:0)

onClick =()=&gt; this.sortable(0)。如果在这种情况下使用任何类型的循环,则必须将索引传递给另一个函数以传递正确的索引值。请参阅此链接以获取解释 React OnClick for item not working

答案 1 :(得分:0)

我没有看到您的代码实际调用sortTable方法的位置,但我相信这里有一个更大的问题。

除非你有充分的理由,否则你不应该手动进行DOM操作。相反,依靠React操纵DOM,这就是你使用它的原因。您有责任根据内部state及其props来描述组件的显示,这是render()功能应该反映的内容。在您的情况下,行的顺序将取决于当前排序列和排序方向。因此,您可以为sort添加其他状态,该状态可能是包含column排序和direction排序的对象。每当单击一列时,您都会更新sort,这将导致您的组件重新渲染。然后,您的render()函数会在显示行时考虑当前的sort状态。

因此,要渲染行,您可以写:

renderRows() {
  const sortFn = getSortFunction(this.state.sort); // defined elsewhere

  // shallow copy so we don't mutate the state
  return [ ...this.state.rows ]
    .sort(sortFn)
    .map((row, i) => (
      <tr key={i}>
        { row.map((cell, j) => <td key={j}>{ cell }</td>) }
      </tr>
    ));
}

render() {
  return (
    <table>
      <thead>{ renderHeader() }</thead>
      <tbody>{ renderRows() }</tbody>
    </table>
  );
}

此外,在呈现React应用程序时,ReactDOM.render()调用会使用您提供的React元素替换DOM元素的内容。通常的做法是将<div id="root">用作应用容器,然后将其内容替换为您的应用。

ReactDOM.render(<App />, document.getElementById("root"));