Сегодня мы буде создавать интерактивную таблицу с помощью библиотеки React.js
Нам нужно создать простую таблицу, которая будет выводить данные с сервера и предоставит нам некоторые возможности, в частности - вывод всех данных из ячейки на страницу отдельно, сортировку данных в столбцах таблицы. До загрузки данных с сервера, должен показываться слайдер загрузки.
Готовое приложение здесь
Приложение будем создавать с помощью готового решения от разработчиков Facebook - create-react-app.
Я не буду на этом останавливаться, потому что много раз уже рассказывал об этом в постах о React. О самом приложении, вы сможете подробно почитать на странице github - /facebook/create-react-app
Здесь все просто. Создаем папку с проектом переходим в нее и ... Начнем с удаления ненужных файлов и удаления их импортов.
В папке src я оставил только три файла: App.js, index.js и serviceWorker.js
В файле App.js я удалил все ненужные подключения (импорты) и внутренность компонента
или, если вы используете yarn
Я буду использовать npm, поэтому здесь и далее команды для npm.
После того, как закончится установка, в файле package.json, в разделе зависимостей - dependencies вы увидите установленные пакеты
Теперь нам нужно его подключить в файле index.js
Теперь мы можем запустить сервер и проверить подключение Bootstrap и работоспособность приложения.
В консоли набираем:
Сервер запустится и наше приложение запустится на порту 3000.
Для остановки сервера, вы можете использовать сочетание клавиш Ctrl + C
На фото выше, вы можете видеть, что сервер запустился, приложение работает и Bootstrap подключен ( на контейнер действуют стили самого Bootstrap - отмечено красным).
На этом этапе код по ссылке: react-table-abc
ci-m (здесь и далее - коммит) "deleted unnecessary files and import bootstrap"
Если перейти по ней, то можно увидеть все данные, которые будут переданы нам в формате
Для читабельности данных и их красивого отображения. я использую расширение для браузера - JSONView
Написание кода в новом формате, позволяет нам использовать новые возможности, а именно асинхронные запросы-
Для получения данных, мы используем метод
Вся конструкция в компоненте App будет выглядеть так:
Таким образом мы вернем в объект
Для отображения объекта
Если посмотреть сейчас в консоль приложения, то мы увидим:
Если посмотреть на отдельный элемент, то мы увидим все данные, которые нам нужно будет отобразить на странице в виде таблицы:
Мы увидим, что в объекте
На этом этапе код по ссылке: react-table-abc
ci -m "Asinc request to the date for table"
Для решения этой задачи, мы не будем выдумывать свой велосипед и возьмем готовое решение с сайта Pure CSS Loaders.
В папке src мы создадим отдельную, одноименную папку для компонента Loader и поместим туда два файла: Loader.js и Loader.css.
Теперь выбираем на сайте понравившийся индикатор, нажимаем на него и получаем код для css и html.
Как вы догадались, css-код мы отправляем в файл Loader.css практически без изменений. Я только изменил цвет индикатора на синий и добавил ему позиционирование по центру страницы:
В файле Loader.js мы импортируем сам React для создания компонента и стили.
Далее, создадим "глупый" простой компонент, как безымянную функцию и сразу же ее экспортируем. Функция будет возвращать пустой
Это поможет избежать ненужных ошибок и сделает ваше приложение более легким для работы, загрузки и масштабирования, обслуживания в дальнейшем.
Сейчас нам нужно импортировать компонент Loader в компонент App и вывести его на страницу, вместо текста "MyApp".
Это очень простая задача и я не буду на ней останавливаться. Если не получится сделать самостоятельно, то я приведу код App компонента полностью ниже.
На этом этапе код по ссылке: react-table-abc
ci -m "Loader"
Так как, мы договорились создавать "умные компоненты" только там где нужно, то этот компонент будет тоже простым.
В него мы будем выводить данные в виде таблицы. Для этого мы будем использовать готовую таблицу, которую мы возьмем с сайта Bootstrap Bootstrap Tables- отсюда полностью скопируем
В компоненте мы будем возвращать саму таблицу
Если я, все-таки вас запутал, то не огорчайтесь, начнем все по порядку.
Представим, что наш компонент Table уже получил эти данные в виде
Таким образом, мы выводим нужные нам ячейки (столбцы) в оду строку таблицы для каждого отдельного объекта данных.
Теперь, переходим в компонент App и там импортируем нашу таблицу - компонент Table
Сейчас нам нужно сделать так, чтобы пока идет загрузка, показывать компонент Loader, как только загрузка закончилась, то Table
Для этого мы в компоненте App создадим состояние -
В методе
В сам компонент Table мы передадим данные, о которых говорили выше -
Теперь нам нужно изменить
Для этого мы в методе жизненного цикла компонента, после получения данных, вместо вывода их в консоль, будем менять состояние компонента:
В функции изменения состояния мы имеем право просто написать
Все вместе:
Посмотрим на приложение:
Мы увидим предупреждение. Это значит, что нам передали два элемента с одинаковым
Теперь у нас есть таблица с данными.
На этом этапе код по ссылке: react-table-abc
ci -m "create table"
Для этого нам нужно написать функцию сортировки (мы это сделаем с помощью библиотеки Lodash), передать ее в виде
Начнем в обратном порядке, а именно - на заголовки таблицы повесим события
Table.js
Теперь, нам нужно передать эту функцию в виде свойства компоненту
Сразу над методом
Для сохранения контекста мы напишем ее в виде стрелочной функции.
Название параметру -
В методе мы посмотрим, что из себя будут представлять эти поля, которые мы передаем в эту функцию:
Как видно на фото выше, при клике мы получаем значение столбца. который нам нужно фильтровать.
Добавим ее в наш проект.
После того, как завершится установка, в зависимостях (package.json) появится нужная нам библиотека:
Теперь нам нужно ее импортировать. Для этого идем в файл App.js и добавляем следующую строку:
В методе
Это делаем для того, чтобы у нас никак не менялся
Теперь нам нужно отсортировать эту копию массива по определенному полю, которое мы передаем в функцию в виде аргумента -
Направление мы сохраним в стейтах как
Теперь нам нужно определить направление. Назовем переменную -
Создадим переменную для отсортированного массив -
В итоге мы получаем отсортированные данные и нам остается изменить состояние нашего компонента -
Здесь важно определить поля, которые мы будем менять.
Поле
Метод onSort компонента App.js полностью:
Теперь можно посмотреть на результат в браузере. Нажимаем на LastName и происходит сортировка в этом столбце по алфавиту.
Еще раз нажимаем и сортировка начинается в обратном порядке:
Таким образом можно нажимать на названия любого столбца и получать сортировку элементов в прямом или обратном порядке.
Мы их передали в наш компонент и теперь мы их проверим.
Проще говоря, если в sortField нам будет передан 'id', то мы покажем некий компонент - <small>{props.sort}</small> на экране (в данном случае в поле заголовка - ID), а если нет, то ничего не покажем - null.
Такие конструкции, только с соответствующими значениями мы добавим во все поля заголовка таблицы:
Посмотрим в браузере. Если нажать на заголовок - ID, то появится метод сортировки - (asc), а при повторном нажатии - (desc)
Единственная проблема, что при перезагрузки страницы, мы по умолчанию в поле ID показываем сортировку asc, хотя в действительности никакой сортировки еще нет.
Поэтому, чтобы не путать пользователя, мы в компоненте
Теперь, при перезагрузке или получении данных с сервера, мы всегда будем видеть отсортированный массив. Таким образом направление добавляется вполне правомерно.
Сейчас мы можем проверить сортировку по всем полям.
На этом этапе код по ссылке: react-table-abc
ci -m "Sort items in columns and display sorting options in the header."
Как задание для тренировки: вы можете заменить строку
Для этого мы в компоненте
передадим туда
Table.js часть:
Сейчас нам нужно написать сам метод в компоненте
Выше метода
Проверим, что же у нас будет в консоли?
При клике по строке, мы получаем все данные пользователя в консоль. Для того, чтобы вывести данные, нам нужно в стейт добавить новое свойство -
И вместо вывода в консоль данных объекта в методе
Теперь в этом же компоненте мы будем выводить детальное отображение этой строчки. Для этого нам потребуется новый компонент DetailRowView и некоторая логика:
Если в this.state.row что-то есть, то покажем новый компонент, а если нет, то ничего не покажем.
В компонент мы передадим состояние.
Не забываем импортировать этот компонент в
Посмотрим в браузере.
При клике по любому компоненту внутри таблицы, мы будем видеть текст внизу.
Данные из props получим сразу путем деструктуризации.
Теперь нам стоит посмотреть на то, что получает данный компонент в консоли на вкладке Networks
Зная данные, которые мы получаем из сети, не составляет труда вывести их из
DetailRowView.js
Если теперь мы посмотрим на то, что получилось и нажмем на какие-либо данные любого пользователя, то внизу, под таблицей, мы увидим ВСЕ данные пользователя в удобном формате.
Таким образом мы справились с начальным заданием и создали интерактивную таблицу с помощью React. Предела совершенству нет. Вы можете самостоятельно сделать пагинацию, добавит компонент для вывода порядка сортировки и много чего еще.
На этом этапе код по ссылке: react-table-abc
ci -m "data output from the table row to the page"
Продолжение ->
Удачного кодирования!
Нам нужно создать простую таблицу, которая будет выводить данные с сервера и предоставит нам некоторые возможности, в частности - вывод всех данных из ячейки на страницу отдельно, сортировку данных в столбцах таблицы. До загрузки данных с сервера, должен показываться слайдер загрузки.
Готовое приложение здесь
Приложение будем создавать с помощью готового решения от разработчиков Facebook - create-react-app.
Я не буду на этом останавливаться, потому что много раз уже рассказывал об этом в постах о React. О самом приложении, вы сможете подробно почитать на странице github - /facebook/create-react-app
Здесь все просто. Создаем папку с проектом переходим в нее и ... Начнем с удаления ненужных файлов и удаления их импортов.
В папке src я оставил только три файла: App.js, index.js и serviceWorker.js
В файле App.js я удалил все ненужные подключения (импорты) и внутренность компонента
App
, а так как мы будем использовать Bootstrap для отображения наших компонентов, то я сразу добавил компоненту класс Bootstrap - className="container"
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<div className="container">
MyApp
</div>
);
}
}
export default App;
Устанавливаем и подключаем Bootstrap
Для простоты реализации наших задач с таблицей, мы будем использовать библиотеку Bootstrap. Для ее установки нам необходимо, находиться в папке нашего проекта (Если вы используете Visual Studio Code, то просто - создать терминал, а если КС - командную строку Windows или терминал, то перейти в папку проекта и набрать:
npm install bootstrap
или, если вы используете yarn
yarn add bootstrap
Я буду использовать npm, поэтому здесь и далее команды для npm.
После того, как закончится установка, в файле package.json, в разделе зависимостей - dependencies вы увидите установленные пакеты
"bootstrap": "^4.2.1"
Теперь нам нужно его подключить в файле index.js
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import * as serviceWorker from './serviceWorker'; import 'bootstrap/dist/css/bootstrap.min.css' ReactDOM.render(, document.getElementById('root')); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: http://bit.ly/CRA-PWA serviceWorker.unregister();
Теперь мы можем запустить сервер и проверить подключение Bootstrap и работоспособность приложения.
В консоли набираем:
npm start
Сервер запустится и наше приложение запустится на порту 3000.
Для остановки сервера, вы можете использовать сочетание клавиш Ctrl + C
На фото выше, вы можете видеть, что сервер запустился, приложение работает и Bootstrap подключен ( на контейнер действуют стили самого Bootstrap - отмечено красным).
На этом этапе код по ссылке: react-table-abc
ci-m (здесь и далее - коммит) "deleted unnecessary files and import bootstrap"
Получаем данные.
Данные для таблицы мы будем получать из сети по этой ссылке. http://www.filltext.com/?rows=32&id={number|1000}&firstName={firstName}&lastName={lastName}&email={email}&phone={phone|(xxx)xxx-xx-xx}&address={addressObject}&description={lorem|32}Если перейти по ней, то можно увидеть все данные, которые будут переданы нам в формате
json
Для читабельности данных и их красивого отображения. я использую расширение для браузера - JSONView
Очень важно здесь понять, что нам нужно получить данные из сети тогда, когда у нас будет уже сформировано DOM дерево.Именно поэтому мы будем использовать жизненный цикл React компонента, а именно -
componentDidMount
Написание кода в новом формате, позволяет нам использовать новые возможности, а именно асинхронные запросы-
asinc/await
. Если вы хотите вспомнить детали, то посмотрите в моем блоге
Для получения данных, мы используем метод
fetch()
в который передадим эту ссылку внутри обратных кавычек.
Вся конструкция в компоненте App будет выглядеть так:
import React, { Component } from 'react'; import Loader from './Loader/Loader'; import Table from './Table/Table'; class App extends Component { async componentDidMount() { const response = await fetch(` http://www.filltext.com/?rows=32&id={number|1000}&firstName={firstName}&lastName={lastName}&email={email}&phone={phone|(xxx)xxx-xx-xx}&address={addressObject}&description={lorem|32}`) const data = await response.json() console.log(data) } render() { return ( <div className="container"> MyApp </div> ); } } export default App;
Таким образом мы вернем в объект
response
промис.
А в объект data
положим результат работы response
и его метода - JSON
.
Для отображения объекта
data
мы его выведем в консоль.
Если посмотреть сейчас в консоль приложения, то мы увидим:
Если посмотреть на отдельный элемент, то мы увидим все данные, которые нам нужно будет отобразить на странице в виде таблицы:
Мы увидим, что в объекте
data
содержатся все те данные, которые мы хотели получить из сети по запросу.
На этом этапе код по ссылке: react-table-abc
ci -m "Asinc request to the date for table"
Индикатор загрузки.
Сейчас перед нами стоит задача отображать индикатор загрузки на странице до тех пор, пока мы не получили данные по сети для формирования таблицы.Для решения этой задачи, мы не будем выдумывать свой велосипед и возьмем готовое решение с сайта Pure CSS Loaders.
В папке src мы создадим отдельную, одноименную папку для компонента Loader и поместим туда два файла: Loader.js и Loader.css.
Теперь выбираем на сайте понравившийся индикатор, нажимаем на него и получаем код для css и html.
Как вы догадались, css-код мы отправляем в файл Loader.css практически без изменений. Я только изменил цвет индикатора на синий и добавил ему позиционирование по центру страницы:
.lds-dual-ring { width: 64px; height: 64px; position: absolute; top: 50%; left: 50%; } .lds-dual-ring:after { content: " "; display: block; width: 46px; height: 46px; margin: 1px; border-radius: 50%; border: 5px solid rgb(40, 3, 253); border-color: rgb(40, 3, 253) transparent rgb(40, 3, 253) transparent; animation: lds-dual-ring 1.2s linear infinite; } @keyframes lds-dual-ring { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
В файле Loader.js мы импортируем сам React для создания компонента и стили.
Далее, создадим "глупый" простой компонент, как безымянную функцию и сразу же ее экспортируем. Функция будет возвращать пустой
div
элемент, которому мы дадим класс, который взяли из html - кода нашего индикатора загрузки:
import React from 'react'; import './Loader.css'; export default () => <div className="lds-dual-ring" />
При написании компонентов, стоит помнить, что задавать их через классы и делать их "умными" нужно только тогда, когда компонент будет хранить какую-то логику действий. А если он только отображает какой-то элемент на странице, то лучше всего написать его простой функцией.
Это поможет избежать ненужных ошибок и сделает ваше приложение более легким для работы, загрузки и масштабирования, обслуживания в дальнейшем.
Сейчас нам нужно импортировать компонент Loader в компонент App и вывести его на страницу, вместо текста "MyApp".
Это очень простая задача и я не буду на ней останавливаться. Если не получится сделать самостоятельно, то я приведу код App компонента полностью ниже.
На этом этапе код по ссылке: react-table-abc
ci -m "Loader"
Формируем таблицу.
Для таблицы нам потребуется компонент Table для которого мы создадим отдельную папку в папке src и в ней файл Table.js.Так как, мы договорились создавать "умные компоненты" только там где нужно, то этот компонент будет тоже простым.
В него мы будем выводить данные в виде таблицы. Для этого мы будем использовать готовую таблицу, которую мы возьмем с сайта Bootstrap Bootstrap Tables- отсюда полностью скопируем
thead
таблицы. В коде ниже - отметил синим.
В компоненте мы будем возвращать саму таблицу
table className="table"
, внутри поместим thead
и ниже него создадим tbody
, куда мы и будем выводить нами полученные данные из переменной data, которые мы передадим в виде props
нашему компоненту Table в компоненте App.
Если я, все-таки вас запутал, то не огорчайтесь, начнем все по порядку.
Представим, что наш компонент Table уже получил эти данные в виде
props
с именем data
. Наша задача вывести их по отдельности в каждую ячейку таблицы. Для этого мы используем метод map()
В коде ниже отметил красным.
import React from 'react'; export default props => ( <table className="table"> <thead> <tr> <th>ID</th> <th>First Name</th> <th>Last Name</th> <th>E-mail</th> <th>Phone</th> </tr> </thead> <tbody> { props.data.map(item =>( <tr key={item.id}> <td>{item.id}</td> <td>{item.firstName}</td> <td>{item.lastName}</td> <td>{item.email}</td> <td>{item.phone}</td> </tr> ))} </tbody> </table> )
Таким образом, мы выводим нужные нам ячейки (столбцы) в оду строку таблицы для каждого отдельного объекта данных.
Теперь, переходим в компонент App и там импортируем нашу таблицу - компонент Table
import Table from './Table/Table';
Сейчас нам нужно сделать так, чтобы пока идет загрузка, показывать компонент Loader, как только загрузка закончилась, то Table
Для этого мы в компоненте App создадим состояние -
state
, в котором создадим поле isLoading:
со значением true
и поле data
, которое равно пустому массиву.
import React, { Component } from 'react'; import Loader from './Loader/Loader'; import Table from './Table/Table'; class App extends Component { state ={ isLoading: true, data: [], } async componentDidMount() { const response = await fetch(` http://www.filltext.com/?rows=32&id={number|1000}&firstName={firstName}&lastName={lastName}&email={email}&phone={phone|(xxx)xxx-xx-xx}&address={addressObject}&description={lorem|32}`) const data = await response.json() console.log(data) } render() { return ( <div className="container"> { this.state.isLoading ? <Loader /> : <Table data={this.state.data} /> } </div> ); } } export default App;
В методе
render
мы проверим. Если this.state.isLoading
, то мы показываем компонент Loader, а если данные уже загрузили, то показываем таблицу.
В сам компонент Table мы передадим данные, о которых говорили выше -
data={this.state.data}
Теперь нам нужно изменить
state
, как только загрузятся данные.
Для этого мы в методе жизненного цикла компонента, после получения данных, вместо вывода их в консоль, будем менять состояние компонента:
async componentDidMount() {
const response = await fetch(` http://www.filltext.com/?rows=32&id={number|1000}&firstName={firstName}&lastName={lastName}&email={email}&phone={phone|(xxx)xxx-xx-xx}&address={addressObject}&description={lorem|32}`)
const data = await response.json()
// console.log(data)
this.setState({
isLoading: false,
data
})
}
В функции изменения состояния мы имеем право просто написать
data
, потому что у нас совпадают ключ и значение (data: data
).
Все вместе:
import React, { Component } from 'react'; import Loader from './Loader/Loader'; import Table from './Table/Table'; class App extends Component { state ={ isLoading: true, data: [], } async componentDidMount() { const response = await fetch(` http://www.filltext.com/?rows=32&id={number|1000}&firstName={firstName}&lastName={lastName}&email={email}&phone={phone|(xxx)xxx-xx-xx}&address={addressObject}&description={lorem|32}`) const data = await response.json() // console.log(data) this.setState({ isLoading: false, data }) } render() { return ( <div className="container"> { this.state.isLoading ? <Loader /> : <Table data={this.state.data} /> } </div> ); } } export default App;
Посмотрим на приложение:
Мы увидим предупреждение. Это значит, что нам передали два элемента с одинаковым
id
, поэтому нам нужно внести некоторые изменения в наш ключ - key
в файле Table.js и сделать его равным не просто id
, а прибавить к нему, например телефонный номер для большей уникальности:
<tr key={item.id + item.phone}>
Теперь у нас есть таблица с данными.
На этом этапе код по ссылке: react-table-abc
ci -m "create table"
Сортировка элементов в таблице.
Наша задача сделать так, чтобы по клику на заголовок таблицы, данные в каждом столбце сортировались в порядке возрастания (чисел и по алфавиту). При повторном клике, сортировка в обратную сторону.Для этого нам нужно написать функцию сортировки (мы это сделаем с помощью библиотеки Lodash), передать ее в виде
props
компоненту Table
, повесить событие onClick
с этой функцией на заголовок таблицы и передать в эту функцию название столбца ( id, firstName, lastName или phone ).
Начнем в обратном порядке, а именно - на заголовки таблицы повесим события
onClick
контекст мы передавать не будем, поэтому первым параметром передадим -null
, а вторым параметром передадим название столбца, который нужно сортировать.
onClick={props.onSort.bind(null, 'id')}
Table.js
<tr> <th onClick={props.onSort.bind(null, 'id')}>ID</th> <th onClick={props.onSort.bind(null, 'firstName')}>First Name</th> <th onClick={props.onSort.bind(null, 'lastName')}>Last Name</th> <th onClick={props.onSort.bind(null, 'email')}>E-mail</th> <th onClick={props.onSort.bind(null, 'phone')}>Phone</th> </tr>
Теперь, нам нужно передать эту функцию в виде свойства компоненту
<Table />
:
onSort={this.onSort}
{
this.state.isLoading
? <Loader />
: <Table
data={this.state.data}
onSort={this.onSort}
/>
}
Сразу над методом
render()
, компонента App мы напишем саму эту функцию.
Для сохранения контекста мы напишем ее в виде стрелочной функции.
Название параметру -
sortField
дали произвольное.
onSort = sortField => ( console.log(sortField) )
В методе мы посмотрим, что из себя будут представлять эти поля, которые мы передаем в эту функцию:
Как видно на фото выше, при клике мы получаем значение столбца. который нам нужно фильтровать.
Собственно сортировка.
Для упорядочивания элементов по алфавиту и в цифровом порядке, мы обратимся к orderBy Lodash.Добавим ее в наш проект.
npm i --save lodash
После того, как завершится установка, в зависимостях (package.json) появится нужная нам библиотека:
Теперь нам нужно ее импортировать. Для этого идем в файл App.js и добавляем следующую строку:
import _ from 'lodash';
В методе
onSort
создадим копию нашего массива:
const cloneData = this.state.data.concat();
Это делаем для того, чтобы у нас никак не менялся
state.data
в состоянии компонента.
Теперь нам нужно отсортировать эту копию массива по определенному полю, которое мы передаем в функцию в виде аргумента -
sortField
и в определенном направлении
Направление мы сохраним в стейтах как
sort:'asc'
. Стоит помнить, что оно может меняться на 'desc'
state ={ isLoading: true, data: [], sort: 'asc', // 'desc' sortField: 'id', // поле по умолчанию }
Теперь нам нужно определить направление. Назовем переменную -
sortType
и проверим, что у нас лежит в свойстве sort
наших стейт. И если значение переменной будет 'asc'
, то мы меняем его на 'desc'
и наоборот.
const sortType = this.state.sort === 'asc' ? 'desc' : 'asc';
Создадим переменную для отсортированного массив -
orderedData
. Метод сортировки напишем по примеру документации. передадим туда копию нашего массива - cloneData
, вторым параметром нам нужно указать поле по которому мы сортируем - sortField
и направление - sortType
const orderedData = _.orderBy(cloneData, sortField, sortType);
В итоге мы получаем отсортированные данные и нам остается изменить состояние нашего компонента -
this.setState({})
.
Здесь важно определить поля, которые мы будем менять.
Поле
data
мы меняем на orderedData
, sort
на sortType
и поле sortField
на sortField
.
sortField
нужно для того чтобы мы знали какое поле мы сортировали. Поэтому добавили его в наши стейт с значением 'id'
по умолчанию.
Метод onSort компонента App.js полностью:
onSort = sortField => { const cloneData = this.state.data.concat(); const sortType = this.state.sort === 'asc' ? 'desc' : 'asc'; const orderedData = _.orderBy(cloneData, sortField, sortType); this.setState({ data: orderedData, sort: sortType, sortField }) }
Теперь можно посмотреть на результат в браузере. Нажимаем на LastName и происходит сортировка в этом столбце по алфавиту.
Еще раз нажимаем и сортировка начинается в обратном порядке:
Таким образом можно нажимать на названия любого столбца и получать сортировку элементов в прямом или обратном порядке.
Визуальное отображение сортировки.
Во первых мы будем передавать в компонентTable
два параметра из стейта компонента App
. За направление отвечает -sort и за поле - sortField. При изменении сортировки они будут меняться в методе this.setState({})
, который мы написали ранее.
{
this.state.isLoading
? <Loader />
: <Table
data={this.state.data}
onSort={this.onSort}
sort={this.state.sort}
sortField={this.state.sortField}
/>
}
Мы их передали в наш компонент и теперь мы их проверим.
{props.sortField === 'id' ? <small>{props.sort}</small> : null}
Проще говоря, если в sortField нам будет передан 'id', то мы покажем некий компонент - <small>{props.sort}</small> на экране (в данном случае в поле заголовка - ID), а если нет, то ничего не покажем - null.
Такие конструкции, только с соответствующими значениями мы добавим во все поля заголовка таблицы:
<thead> <tr> <th onClick={props.onSort.bind(null, 'id')}> ID {props.sortField === 'id' ? <small>{props.sort}</small> : null} </th> <th onClick={props.onSort.bind(null, 'firstName')}> First Name {props.sortField === 'firstName' ? <small>{props.sort}</small> : null} </th> <th onClick={props.onSort.bind(null, 'lastName')}> Last Name {props.sortField === 'lastName' ? <small>{props.sort}</small> : null} </th> <th onClick={props.onSort.bind(null, 'email')}> E-mail {props.sortField === 'email' ? <small>{props.sort}</small> : null} </th> <th onClick={props.onSort.bind(null, 'phone')}> Phone {props.sortField === 'phone' ? <small>{props.sort}</small> : null} </th> </tr> </thead>
Посмотрим в браузере. Если нажать на заголовок - ID, то появится метод сортировки - (asc), а при повторном нажатии - (desc)
Единственная проблема, что при перезагрузки страницы, мы по умолчанию в поле ID показываем сортировку asc, хотя в действительности никакой сортировки еще нет.
Поэтому, чтобы не путать пользователя, мы в компоненте
App
, в момент получения данных в сет-стейт метода componentDidMount()
добавим сортировку:
async componentDidMount() {
const response = await fetch(` http://www.filltext.com/?rows=32&id={number|1000}&firstName={firstName}&lastName={lastName}&email={email}&phone={phone|(xxx)xxx-xx-xx}&address={addressObject}&description={lorem|32}`)
const data = await response.json()
this.setState({
isLoading: false,
data: _.orderBy(data, this.state.sortField, this.state.sort)
})
}
Теперь, при перезагрузке или получении данных с сервера, мы всегда будем видеть отсортированный массив. Таким образом направление добавляется вполне правомерно.
Сейчас мы можем проверить сортировку по всем полям.
На этом этапе код по ссылке: react-table-abc
ci -m "Sort items in columns and display sorting options in the header."
Как задание для тренировки: вы можете заменить строку
<small>{props.sort}</small>
на отдельный компонент в котором вывести отдельно индикаторы сортировки в виде картинок или иконок.
Вывод информации по клику.
Нам нужно сделать так, чтобы при клике по любой ячейке, строке, выводилась ВСЯ информация о пользователе на страницу, ниже нашей таблицы, отдельно.Для этого мы в компоненте
Table
каждому элементу tr
добавим обработчик события:
onClick={props.onRowSelect.bind(null, item)}
передадим туда
item
Table.js часть:
<tbody>
{ props.data.map(item =>(
<tr key={item.id + item.phone} onClick={props.onRowSelect.bind(null, item)}>
<td>{item.id}</td>
<td>{item.firstName}</td>
<td>{item.lastName}</td>
<td>{item.email}</td>
<td>{item.phone}</td>
</tr>
))}
</tbody>
Сейчас нам нужно написать сам метод в компоненте
App
и передать его в Table
Передаем его в компонент:
{
this.state.isLoading
? <Loader />
: <Table
data={this.state.data}
onSort={this.onSort}
sort={this.state.sort}
sortField={this.state.sortField}
onRowSelect={this.onRowSelect}
/>
}
Выше метода
render
в компоненте App
пишем сам метод, который будет принимать в качестве параметра row
и выведем его в консоль:
onRowSelect = row => ( console.log(row) )
Проверим, что же у нас будет в консоли?
При клике по строке, мы получаем все данные пользователя в консоль. Для того, чтобы вывести данные, нам нужно в стейт добавить новое свойство -
row
state ={
isLoading: true,
data: [],
sort: 'asc', // 'desc'
sortField: 'id',
row: null,
}
И вместо вывода в консоль данных объекта в методе
onRowSelect
сделать изменение стейта:
onRowSelect = row => (
this.setState({row})
)
Теперь в этом же компоненте мы будем выводить детальное отображение этой строчки. Для этого нам потребуется новый компонент DetailRowView и некоторая логика:
{ this.state.row ? <DetailRowView person={this.state.row} /> : null }
Если в this.state.row что-то есть, то покажем новый компонент, а если нет, то ничего не покажем.
В компонент мы передадим состояние.
Создадим сам компонент
В папке src создадим папку- DetailRowView с одноименным js-файлом. Создадим простой компонент и выведем какой-либо текст на экран:import React from 'react'; export default () => ( <div> <h1>DetailRowView</h1> </div> )
Не забываем импортировать этот компонент в
App.js
import DetailRowView from './DetailRowView/DetailRowView';
Посмотрим в браузере.
При клике по любому компоненту внутри таблицы, мы будем видеть текст внизу.
Данные из props получим сразу путем деструктуризации.
({props})
Теперь нам стоит посмотреть на то, что получает данный компонент в консоли на вкладке Networks
Зная данные, которые мы получаем из сети, не составляет труда вывести их из
props
в компоненте. остается просто добавить нормальную верстку для нашего компонента.
DetailRowView.js
import React from 'react'; export default ({person}) => ( <div> <p>Выбран пользователь <b>{person.firstName + ' ' + person.lastName}</b></p> <p> Описание: <br /> <textarea defaultValue={person.description} /> </p> <p>Адрес проживания: <b>{person.address.streetAddress}</b></p> <p>Город: <b>{person.address.city}</b></p> <p>Провинция/штат: <b>{person.address.state}</b></p> <p>Индекс: <b>{person.address.zip}</b></p> </div> )
Если теперь мы посмотрим на то, что получилось и нажмем на какие-либо данные любого пользователя, то внизу, под таблицей, мы увидим ВСЕ данные пользователя в удобном формате.
Таким образом мы справились с начальным заданием и создали интерактивную таблицу с помощью React. Предела совершенству нет. Вы можете самостоятельно сделать пагинацию, добавит компонент для вывода порядка сортировки и много чего еще.
На этом этапе код по ссылке: react-table-abc
ci -m "data output from the table row to the page"
Продолжение ->
Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.
Удачного кодирования!