问题
I have an array of objects. i want to access class method inside object function property. How to implement this? please help me. I wrote smth like this:
render() {
tableTh = [
{name: i18n.t('ExtendedModalBar.naming'), style:{}, handleSort () {}},
...
]
...
}
I am trying to write someth like this:
class Table extends Component {
handleSort() {
}
...
render() {
}
}
My table headers are formed dynamically:
<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>
I must implement sorting of table columns. If tables are formed statically it is easy to attach onclick to th tag. but if code was written like this, i am stuck. How to write method in the class that will be accessible from inside property of objects (array of objects) ? And I need sorting in both directions ascending and descending. My table column should change own sorting direction when I click on its table header. Any answers will be taken into acccount. Thanks in advance
回答1:
The problem with having the state-changing function on the state itself is that this inherently makes it difficult to manipulate the state.
var data = [
{ name: 'a', change: /* ??? */ },
{ name: 'b', change: /* ??? */ },
{ name: 'c', change: /* ??? */ }
]
// How do we write the function ??? to change the order of data?
It is much simpler to lift the data-manipulation logic at a higher level (outside of the data itself).
In this case, we would put the data-manipulation logic on the class itself as opposed to within each item.
We can do this by leveraging the state in React.
A state is used to hold any (dynamic) presentational (rendered) data for a component. An example of dynamic (changing) presentational data would be a table that sorts its columns.
The reason we want to put presentational data in the state is because React allows us to re-trigger the presentation (by re-rendering) to always show the latest values for our data.
We can achieve this just by changing the data itself and not any presentational logic. This is why React component structure is referred to as declarative.
Anytime the state is updated, React will call the render
function to obtain the component structure with the latest state changes and display those on the appropriate medium (in your case the DOM)
Here's one way to incorporate state to create a sortable table:
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>
Using hooks the code becomes a bit more readable (click for the CodeSandbox example since SO doesn't support React 16.8 yet):
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"));
回答2:
Change the click handler of the header from onClick={obj.handleSort}
to onClick={e => handleSort(columnName, sortDirection)
. Values of columnName
and sortedDirection
are passed down from parent component
handleSort
in Table
component will be able to accept parameter columnName
and sortDirection
to manipulate data.
Check out this sample implementation
https://codesandbox.io/embed/6lmk0q3w5z?fontsize=14
来源:https://stackoverflow.com/questions/55015470/how-to-create-a-sortable-table-in-react-how-to-access-class-method-from-the-sor