如何在 React 中创建可排序的表?如何从排序的对象访问类方法?
Posted
技术标签:
【中文标题】如何在 React 中创建可排序的表?如何从排序的对象访问类方法?【英文标题】:How to create a sortable table in React? How to access class method from the sorted objects? 【发布时间】:2019-07-27 16:01:45 【问题描述】:我有一个对象数组。我想访问对象函数属性中的类方法。如何实施?请帮我。我是这样写的:
render()
tableTh = [
name: i18n.t('ExtendedModalBar.naming'), style:, handleSort () ,
...
]
...
我正在尝试这样写:
class Table extends Component
handleSort()
...
render()
我的表头是动态形成的:
<thead>
<tr>
<th style= width: "50px" >
<Checkbox
checked=this.state.selectedAll
onChange=() => this.selectAll()
/>
</th>
tableTh.map((obj, index) =>
return (
<th key=index.toString() style=obj.style onClick=obj.handleSort>
obj.name
</th>
);
)
</tr>
</thead>
我必须实现表格列的排序。如果表格是静态形成的,则很容易将 onclick 附加到标签。但如果代码是这样写的,我就卡住了。如何在类中编写可从对象内部属性(对象数组)访问的方法?我需要在升序和降序两个方向上进行排序。当我单击表头时,我的表列应该改变自己的排序方向。任何答案都将被考虑在内。提前致谢
【问题讨论】:
有什么特殊原因需要这样编写代码吗?我认为更好的方法是在您的Table
类中使用 handleSort
,然后在 onClick 侦听器中将对象传递给它:() => this.handleSort(obj)
因为不是我的代码,而且有很多表,我之前的“handleSort”函数接受两个参数,columnName 和 dataToSort。我将此功能附加到表格的每一列。但在这种情况下,如何将特定列与特定数据进行排序?
看看这个codesandbox.io/embed/6lmk0q3w5z?fontsize=14
【参考方案1】:
在状态本身上具有状态更改功能的问题在于,这固有地使得操作状态变得困难。
var data = [
name: 'a', change: /* ??? */ ,
name: 'b', change: /* ??? */ ,
name: 'c', change: /* ??? */
]
// How do we write the function ??? to change the order of data?
在更高级别(数据本身之外)提升数据操作逻辑要简单得多。
在这种情况下,我们会将数据操作逻辑放在类本身而不是在每个项目中。
我们可以通过在 React 中利用 state 来做到这一点。
状态用于保存组件的任何(动态)表示(渲染)数据。动态(不断变化的)展示数据的一个示例是对其列进行排序的表格。
我们想要将展示数据放入状态的原因是因为 React 允许我们重新触发展示(通过重新渲染)以始终显示我们数据的最新值。
我们可以通过更改数据本身而不是任何表示逻辑来实现这一点。这就是为什么 React 组件结构被称为declarative。
每当状态更新时,React 都会调用render
函数来获取具有最新状态更改的组件结构,并将其显示在适当的介质上(在您的情况下为DOM)
这是一种合并状态以创建可排序表的方法:
class Table extends React.Component
constructor(props)
super(props);
this.state =
sortDirection: "asc", // we start with ascending order by default
selectedHeaderIndex: 0 // we start by sorting based on the first header (the one in position 0)
;
this.ascComparator = (row1, row2) =>
row1[this.state.selectedHeaderIndex].localeCompare(
row2[this.state.selectedHeaderIndex]
);
this.descComparator = (row1, row2) =>
row2[this.state.selectedHeaderIndex].localeCompare(
row1[this.state.selectedHeaderIndex]
);
this.flipSortDirection = () =>
this.state.sortDirection === "asc" ? "desc" : "asc";
render()
const headers, rows = this.props.table;
const comparator =
this.state.sortDirection === "asc"
? this.ascComparator
: this.descComparator;
// sort the rows based on the selected header
const sortedRows = rows.sort(comparator);
return (
<table>
<thead>
headers.map((header, i) => (
<th
onClick=() =>
this.setState(
// if we clicked on the already selected index, we flip the sort direction
sortDirection:
this.state.selectedHeaderIndex === i
? this.flipSortDirection()
: "asc",
selectedHeaderIndex: i
);
>
header
</th>
))
</thead>
<tbody>
sortedRows.map(row => (
<tr>
row.map(cell => (
<td>cell</td>
))
</tr>
))
</tbody>
</table>
);
const table =
headers: ["h1", "h2", "h3"],
rows: [["a", "9", "+"], ["b", "6", "-"], ["c", "3", "="]]
;
ReactDOM.render(<Table table=table />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
使用hooks,代码变得更易读(click for the CodeSandbox example,因为 SO 还不支持 React 16.8):
function Table( table )
const headers, rows = table;
const [selectedHeaderIndex, setSelectedHeaderIndex] = React.useState(0); // we start by sorting based on the first header (the one in position 0)
const [sortDirection, setSortDirection] = React.useState("asc"); // we start with ascending order by default
// determine the sorting comparator based on the sorting direction
const comparator =
sortDirection === "asc"
? (row1, row2) =>
row1[selectedHeaderIndex].localeCompare(row2[selectedHeaderIndex])
: (row1, row2) =>
row2[selectedHeaderIndex].localeCompare(row1[selectedHeaderIndex]);
const flipSortDirection = () => (sortDirection === "asc" ? "desc" : "asc");
// sort the rows based on the selected header
const sortedRows = rows.sort(comparator);
return (
<table>
<thead>
headers.map((header, i) => (
<th
onClick=() =>
setSelectedHeaderIndex(i);
setSortDirection(
selectedHeaderIndex === i ? flipSortDirection() : "asc"
);
>
header
</th>
))
</thead>
<tbody>
sortedRows.map(row => (
<tr>
row.map(cell => (
<td>cell</td>
))
</tr>
))
</tbody>
</table>
);
const table =
headers: ["h1", "h2", "h3"],
rows: [["a", "9", "+"], ["b", "6", "-"], ["c", "3", "="]]
;
ReactDOM.render(<Table table=table />, document.querySelector("#root"));
【讨论】:
我忘了说我需要在升序和降序两个方向上进行排序。如何实施?当我点击表格标题时,我的表格列应该改变自己的排序方向。 感谢您的回答。但是现在,它不会双向排序。它依次排序,这有点不正确 之所以在构造函数中写它是因为使用箭头函数处理this
绑定更简单。您绝对可以在类本身上移动这些功能,但请确保您 bind the context properly.
我什么都明白了,但我仍然无法实现排序,因为事实上,我的表格数据位于另一个组件中的组件之外。当我单击选择项目按钮时,元素表会出现在模式窗口中。如何从另一个组件获取这些数据?例如在另一个组件中:代码是:selectedItems=this.state.modalItems modalItems:this.state.devices。另一个组件导入 modalBar,我的表格在其中呈现
另一个组件中的所有 dataToSort。它导入并使用我的表所在的 modalWindow 组件。如何对这些数据进行排序如何获取它们?我必须能够在模态窗口中对表格列进行排序【参考方案2】:
将标题的点击处理程序从onClick=obj.handleSort
更改为onClick=e => handleSort(columnName, sortDirection)
。 columnName
和 sortedDirection
的值是从父组件传下来的
Table
组件中的handleSort
将能够接受参数columnName
和sortDirection
来操作数据。
查看此示例实现
https://codesandbox.io/embed/6lmk0q3w5z?fontsize=14
【讨论】:
以上是关于如何在 React 中创建可排序的表?如何从排序的对象访问类方法?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 uiimagepickercontroller 中创建可裁剪的横幅图像?
如何在 HTML/Javascript 中创建可编辑的组合框?
如何像在 Eclipse 中一样在 IntelliJ 中创建可运行的 JAR