Админка магазина на vue.js. Урок 4. Правим код под новое REST API и расследуем багу
Продолжаем работать над админкой vue. Перед тем, как разбивать наше приложение на компоненты, решил написать один промежуточный урок. В нем мы сделаем две вещи.
Во-первых, перейдем на новое серверное rest api, которое мы реализовали в третьем уроке.
Во-вторых, разберем багу, которая закралась в наш код. Бага интересна тем, что ее не заметили ни я, ни читатели. Нашел случайно, когда работал над третьим уроком с новым rest api.
Но обо всем по порядку.
Переводим клиент на новое REST API
Вспомним, что мы делали в первых двух уроках. Мы работали с тремя сущностями: товары, категории и бренды. Товары и бренды мы получали с сервера одним запросом, а категории вообще вбивали руками. Теперь с новым api мы можем работать с каждой из сущностей по отдельности. Плюс меня немного нервировали эти странные названия полей вроде good_id и good. Сейчас есть сущность товар (product), и у нее есть поля id и title (названия). Точно такие же поля и у брендов с категориями. Универсально и легко запоминается.
Первое, что нужно сделать, это избавиться от здоровенного запроса GET /scripts/catalog.php?needs_data=brands, и вместо него использовать культурные GET products (brands или categories) Для этого мы идем в app.js, в метод mount и меняем его старое содержимое, вот такое
mounted: function() { axios .get('/scripts/catalog.php?needs_data=brands') .then(response => { this.products = response.data.data.goods; this.brands = response.data.data.brands; this.minPrice = this.getMinPrice(); this.maxPrice = this.getMaxPrice(); }); }
на новое, такое
mounted: function() { // Получение товаров axios .get('/admin/api/v1/products') .then(response => { this.products = response.data.records; this.minPrice = this.getMinPrice(); this.maxPrice = this.getMaxPrice(); }); // Получение категорий axios .get('/admin/api/v1/categories') .then(response => { this.categories = response.data.records; }); // Получение брендов axios .get('/admin/api/v1/brands') .then(response => { this.brands = response.data.records; }); }
Здесь мы делаем 3 легковесных запросов вместо одного тяжелого, который возвращает 2 разных сущности - а это нехорошо. Плюс отдельный запрос за категориями позволит нам убрать вручную забитый список. Этим и займемся.
Найдем в data место, где мы набивали руками категории и заменим это на categories: []. Все, намного приятнее, чем старое
categories: [ { id: 1, category: 'Ноутбуки' }, { id: 2, category: 'Смартфоны' }, { id: 3, category: 'Видеокарты' } ]
По сути, вся работа уже сделана, нам остается только пробежаться по коду и заменить некоторые старые поля на новые в соответствии с api.
Вот список изменений.
app.js
1. В компоненте ProductItem меняем good_id на просто id и good меняем на title.
2. В data sortRules меняем good_id на просто id, то же самое в selectSort
3. Вычисляемое поле filteredProducts, в нем меняем category_id на categoryId, brand на brandId и good на title
4. В методе clear тоже меняем good_id на id.
index.html
Здесь замен еще меньше
1. category.category меняем на category.title
2. Меняем старое
на новое
3. Меняем :key="product.good_id" на :key="product.id"
Все изменения в обновленных исходниках
По коду все, теперь поговорим про багу, которую я упоминал в начале статьи.
Правим багу
Открою секрет: мы ее уже поправили, сами того не зная. А в чем эта бага состояла? Давайте вместе и посмотрим :)
Откройте демо предыдущего урока - https://shop.webdevkin.ru/admin/vue/lesson2-filters/. Смотрите, мы высчитали минимальную и максимальную цены, как 11000 и 70000. И в таблице у нас выведено 12 товаров. Обратите внимание на их айдишники: с 1 по 11 и 14й. А где же 12й и 13й? Просто пропущены в базе? Нет. Они возвращаются нам с бекенда и хранятся в памяти, в массиве data.products. Можете убедиться, поставьте минимальную цену товаров 0 и увидите, что 12й и 13й товары появились. Их стоимости 2000 и 6000. Как так, при загрузке же мы вычислили минимальную цену в 11000, почему не 2000?
Вот код, он верный.
getMinPrice: function() { return Number(_.minBy(this.products, 'price').price); }
Дело не в этом коде. Посмотрите, что возвращает запрос, которым мы пользовались до этого урока - https://shop.webdevkin.ru/scripts/catalog.php?needs_data=brands. Обратите внимание, в каком виде у нас возвращается цена товара. Это строка. В этом и заключалась наша ошибка.
Ведь функция lodash minBy использует простое сравнение значений. 2000 < 11000, но "2000" > "11000". Именно поэтому, когда предыдущий запрос возвращал строки, мы получали неправильный результат. А в новой версии мы не поленились и преобразовали данные к нужному типу еще на сервере. Помните, как мы упарывались с подобными штуками?
return array( 'id' => $id, 'title' => $item['good'], 'categoryId' => (int)$item['category_id'], 'brandId' => (int)$item['brand_id'], 'brand' => $item['brand'], 'price' => (int)$item['price'], 'rating' => (int)$item['rating'] );
Все числовые значения мы старательно преобразовали к int и тем самым починили немаленькую багу. Представьте, сколько товаров недосчитались бы мы в нашей админке, если бы и дальше работали со строками.
Мораль такая: следите за типами данных, несмотря на то, что яваскрипт очень лоялен к таким фокусам. Проверяйте данные, которые возвращаются с сервера. Пинайте бэкендщиков, чтобы возвращали числа в нужном формате. Не забывайте делать это, если сами пишете бэкенд. Если нет возможности изменить данные с сервера, преобразовывайте их на клиенте. Так вы сможете избежать таких глупых багов, какой случился у меня :-)
На сегодня все, готовлю следующий урок. Подписывайтесь на рассылку, чтобы первыми узнавать о выходе новых статей ;-)
Все уроки админки на vue.js
- Урок 1. Список товаров
- Урок 2. Фильтры и сортировки
- Урок 3. Новое REST API на чистом PHP
- Урок 4. Правим клиентский код под новое REST API и находим багу
- Урок 5. Разбиваем приложение на компоненты
- Урок 6. Инструмент vue-cli и vue-компоненты
- Урок 7. Flux и Vuex - общие вопросы
- Урок 8. Vuex на практике
- Урок 9. Перерабатываем фильтры
- Урок 10. Добавляем и удаляем бренды
- Урок 11. Обрабатываем ошибки на клиенте и сервере
- Урок 12. Редактируем бренды
- Урок 13. Роутинг
- Урок 14. Карточка товара
Истории из жизни айти и обсуждение кода.