Проблема наличия функции изменения состояния на самом состоянии заключается в том, что это по своей сути затрудняет манипулирование состоянием.
var data = [
{ name: 'a', change: /* ??? */ },
{ name: 'b', change: /* ??? */ },
{ name: 'c', change: /* ??? */ }
]
// How do we write the function ??? to change the order of data?
Гораздо проще поднять логику манипулирования данными на более высокий уровень (вне самих данных).
В этом случае мы бы поместили логику манипулирования данными в сам класс, а не в каждый элемент.
Мы можем сделать это, используя состояние в React.
Состояние используется для хранения любых (динамических) представляемых (отображаемых) данных для компонента. Примером динамических (изменяющихся) презентационных данных может служить таблица, сортирующая столбцы.
Причина, по которой мы хотим перевести презентационные данные в состояние, заключается в том, что React позволяет нам повторно запускать презентацию (путем повторного рендеринга), чтобы всегда показывать самые последние значения для наших данных.
Мы можем достичь этого, просто изменив сами данные, а не какую-либо логику представления. Вот почему структура компонентов React называется декларативной .
Каждый раз, когда состояние обновляется, 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>
При использовании перехватов код становится немного более читабельным ( щелкните для примера CodeSandbox , поскольку 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"));