Главная » React & Redux » "Учёт сотрудников": работа с входящими данными (практика работы со свойствами).

"Учёт сотрудников": работа с входящими данными (практика работы со свойствами).


15.11.2021, 21:17
В созданном списке сотрудников в данный момент одни и те же повторяющиеся данные


В таблице выводятся одинаковые данные, так как они жестко определены в коде в файле employers-list-item.js

Вот строки кода, которые за это отвечают:

Код

             <span className="list-group-item-label">John Smith</span>
             <input type="text" className="list-group-item-input" defaultValue="1000$"/>

Нужно, чтобы вместо повторяющихся одинаковых данных выводились разные данные (разные имена, разные цифры зарплат)

Реализовать можно, используя "пропсы", для этого в файле employers-list.js укажем свойства name(имя) и salary(зарплата) для каждой копии компонента EmployersListItem

Код

const EmployersList = () => {
     return(
         <ul className="app-list list-group">
             <EmployersListItem name="Иванов С." salary={800}/>
             <EmployersListItem name="Кононов В." salary={3000}/>
             <EmployersListItem name="Григорьев А." salary={5000}/>
         </ul>    
     )
}

Теперь можно в файле employers-list-item.js для компонента EmployersListItem передать в качестве аргумента объект props, а жестко зашитые в коде имя и значение зарплаты поменять на props.name и props.salary

Код

const EmployersListItem = (props) => {

     return(
         <li className="list-group-item d-flex justify-content-between">
             <span className="list-group-item-label">{props.name}</span>
             <input type="text" className="list-group-item-input" defaultValue={props.salary + '$'}/>
             <div className='d-flex justify-content-center align-items-center'>
                 <button type="button"
                     className="btn-cookie btn-sm ">
                     <i className="fas fa-cookie"></i>
                 </button>

                 <button type="button"
                         className="btn-trash btn-sm ">
                     <i className="fas fa-trash"></i>
                 </button>
                 <i className="fas fa-star"></i>
             </div>
         </li>     
     )
}

Для props.salary добавлен знак доллара путём конкатенирования двух строк.


Теперь в таблице выводятся разные данные, за счёт использования свойств name и salary и их разных значений

В качестве аргумента вместо props можно сразу деструктурировать этот объект, за счёт чего можно уже не писать props.name и props.salary, а просто указывать name и salary:

Код

const EmployersListItem = ({name,salary}) => {

     return(
         <li className="list-group-item d-flex justify-content-between">
             <span className="list-group-item-label">{name}</span>
             <input type="text" className="list-group-item-input" defaultValue={salary + '$'}/>
             <div className='d-flex justify-content-center align-items-center'>
                 <button type="button"
                     className="btn-cookie btn-sm ">
                     <i className="fas fa-cookie"></i>
                 </button>

                 <button type="button"
                         className="btn-trash btn-sm ">
                     <i className="fas fa-trash"></i>
                 </button>
                 <i className="fas fa-star"></i>
             </div>
         </li>     
     )
}

При деструктуризации объекта мы "распаковываем" вложенный объект или массив в переменные, чтобы потом с ними можно было работать. В правой части указываем тот вложенный объект, который мы распаковываем, а в левой - список названий переменных.

В реальности данные получаются от сервера (те же имена, показатели зарплаты и так далее), в коде выше они назначены вручную для каждой копии компонента EmployersListItem, поэтому, если, к примеру, сотрудников будет очень много, то вручную прописывать эти данные для каждого из них не есть хорошо.

Сымитируем приход данных с сервера в виде массива данных data в компоненте App (файл app.js):

Код

function App() {

     const data = [
         {name: "Иванов С.",salary: 800},
         {name: "Кононов В.",salary: 3000},
         {name: "Григорьев А.",salary: 5000}
     ];

     return(
         <div className="app">
             <AppInfo/>

             <div className="search-panel">
                 <SearchPanel/>
                 <AppFilter/>
             </div>

             <EmployersList/>
             <EmployersAddForm/>
         </div>
     )
}

Ниже в коде мы можем использовать этот массив данных в компоненте EmployersList (так как в "пропсы" компонента можно передавать всё что угодно), для этого добавим ему атрибут с именем data и в качестве его значения укажем массив data

Код

function App() {

     const data = [
         {name: "Иванов С.",salary: 800},
         {name: "Кононов В.",salary: 3000},
         {name: "Григорьев А.",salary: 5000}
     ];

     return(
         <div className="app">
             <AppInfo/>

             <div className="search-panel">
                 <SearchPanel/>
                 <AppFilter/>
             </div>

             <EmployersList data={data}/>  
             <EmployersAddForm/>
         </div>
     )
}

Теперь в файле employers-list.js в качестве аргумента для EmployersList можно указать data, вытащив его из props деструктуризацией

Код

const EmployersList = ({data}) => {
     return(
         <ul className="app-list list-group">
             <EmployersListItem name="Иванов С." salary={800}/>
             <EmployersListItem name="Кононов В." salary={3000}/>
             <EmployersListItem name="Григорьев А." salary={5000}/>
         </ul>    
     )
}

Как теперь вывести для каждого сотрудника его имя и значение зарплаты, пришедшие в массиве с сервера?

Для этого нужно перебрать массив data, а точнее, каждый его элемент, а затем вернуть каждый новый компонент EmployersListItem со своими значениями для name и salary.

В данном случае нужен такой метод перебора массива, который переберёт каждый его элемент, произведёт с ним какие-то действия и вернёт нам новый массив элементов.

Под такую задачу подходит метод map().

Новый массив элементов поместим в какую-нибудь, переменную, например elements, которой мы заменим чуть ниже в коде жестко прописанные ранее копии компонента EmployersListItem

Код

const EmployersList = ({data}) => {

     const elements = data.map(item => {
         return(
             <EmployersListItem name={item.name} salary={item.salary}/>
         )
     })

     return(
         <ul className="app-list list-group">
             {elements}
         </ul>    
     )
}

При переборе item это каждый из объектов массива data, который пришел из пропсов.

Используя spread-оператор, данную запись:

Код

<EmployersListItem name={item.name} salary={item.salary}/>

можно сократить до такой:

Код

<EmployersListItem {...item}/>  

И такая запись будет равнозначной, поскольку spread-оператор возьмёт каждый объект массива data и развернёт его на похожую конструкцию.

На примере:

Код

const obj = {name: "Иванов С.",salary: 800};

const newObj = {...obj};

console.log(newObj); // => { name: 'Иванов С.', salary: 800 }

Выделение отдельного сотрудника в списке за счёт добавления css-класса

В файле employers-list-item.css есть строки, отвечающие за выделение сотрудника в списке другим цветом (конкретно за это отвечает наличие класса .increase у элемента li)

Код

.list-group-item.increase .list-group-item-label, .list-group-item.increase .list-group-item-input {
     color: #e09f3e;
}

Добавим свойство increase для каждого из объектов массива data (в файле app.js), "приходящего с сервера".

В двух объектах значение для increase установим в false, а в одном в true

Код

     const data = [
         {name: "Иванов С.",salary: 800,increase: false},
         {name: "Кононов В.",salary: 3000,increase: true},
         {name: "Григорьев А.",salary: 5000,increase: false}
     ];

В файле employers-list-item.js добавим increase третим аргументом для EmployersListItem

Код

const EmployersListItem = ({name,salary,increase}) => /* тут далее код */

Теперь, вынесем все классы, присваиваемые элементу li, в отдельную переменную classNames, и далее сделаем проверку условия, что если для свойства increase установлено значение true, то к классам в переменной classNames добавляется класс increase (и этот элемент в списке сотрудников выделится другим цветом)

Код

const EmployersListItem = ({name,salary,increase}) => {

     let classNames = "list-group-item d-flex justify-content-between";
     if(increase) {
         classNames += ' increase';
     }

     return(
         <li className={classNames}>
             <span className="list-group-item-label">{name}</span>
             <input type="text" className="list-group-item-input" defaultValue={salary + '$'}/>
             <div className='d-flex justify-content-center align-items-center'>
                 <button type="button"
                     className="btn-cookie btn-sm ">
                     <i className="fas fa-cookie"></i>
                 </button>

                 <button type="button"
                         className="btn-trash btn-sm ">
                     <i className="fas fa-trash"></i>
                 </button>
                 <i className="fas fa-star"></i>
             </div>
         </li>     
     )
}


Если для свойства increase установлено значение true, то к классам в переменной classNames добавляется класс increase (и этот элемент в списке сотрудников выделится другим цветом)

Оптимизируем работу приложения через добавления свойства key

Добавим в данные, приходящие "с сервера", свойство id для каждого из элементов массива data

Код

     const data = [
         {name: 'John C.',salary: 800, increase: false, id: 1},
         {name: 'Alex B.',salary: 3000, increase: true, id: 2},
         {name: 'Micle S.',salary: 5000, increase: false, id: 3}
     ];

а в файле app.js перепишем код EmployersList таким образом:

Код

const EmployersList = ({data}) => {

     const elements = data.map(item => {
         const {id, ...itemProps} = item; /* деструктурируем item, вытаскивая отдельно id, остальное собираем в itemProps */
         return(
             <EmployersListItem key={id} {...itemProps}/>
         )
     })

     return(
         <ul className="app-list list-group">
             {elements}
         </ul>
     )
}

Теперь, благодаря тому, что у каждого EmployersListItem будет свой уникальный ключ (id), React будет проще отслеживать изменения в этих компонентах, будут обновляться только те элементы, которые изменились.

КОММЕНТАРИИ (0)

ТЕГИ МАТЕРИАЛА
props, метод map(), React-приложение
РЕЙТИНГ МАТЕРИАЛА (0.0 / 0)