Когда мы работаем с API, очень часто мы можем столкнуться с некоторыми API, в которых отсутствуют некоторые данные. И рендеринг каждой информации на внешнем интерфейсе становится непростой задачей. Есть несколько способов визуализации таких данных (неполных данных), но один из наиболее эффективных способов — «Необязательное связывание».
В этой статье мы увидим, насколько крутой является опциональная цепочка. Итак, давайте начнем с этого.
Чтобы показать необязательную цепочку в действии, нам понадобится начальная настройка кода. (HTML, CSS, JavaScript)
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <!-- styles link --> <link rel="stylesheet" href="style.css" /> </head> <body> <h2>optional chaining</h2> <br /><br /> <br /><br /> <div class="container"></div> <!-- script --> <script src="script.js"></script> </body> </html>
Здесь, в HTML-коде, у нас есть пустой элемент div с классом «container». Мы будем добавлять наши данные в этот div с помощью JavaScript.
CSS. Просто чтобы он выглядел немного лучше (необязательно).
* { margin: 0; padding: 0; } body { height: 100vh; width: 100vw; display: flex; align-items: center; flex-direction: column; } .container { font-size: 1.2rem; max-width: 500px; width: 500px; } .card-container { display: flex; justify-content: space-between; align-items: center; padding: 1rem; margin: 2.5rem; box-shadow: 3px 3px 5px #888888; border-radius: 5px; cursor: pointer; } .card-container:hover { box-shadow: 5px 5px 8px #5f5f5f; transition: all ease 0.5s; transform: scale(1.1); } h2 { text-transform: capitalize; font-family: "Courier New", Courier, monospace; font-size: 2rem; text-decoration: underline; margin-top: 20px; } .span-container { display: flex; align-items: center; } p { color: gray; } img { width: 150px; height: 150px; border-radius: 50%; }
Теперь наступает важная часть (код JavaScript), в которой мы будем отображать данные.
Для этой демонстрации мы будем использовать массив данных. (он локальный, не исходит из какого-либо API)
ДАННЫЕ
const data = [ { id: 1, name: "Avinash", username: "p4avinash", image: [ { profile: { url: "https://avatars.githubusercontent.com/u/46785501?v=4", }, }, ], }, { id: 2, name: "Ayush", username: "f4ayush", image: [ { profile: { url: "https://avatars.githubusercontent.com/u/41805354?v=4", }, }, ], }, { id: 3, name: "Raushan", image: [{}], }, ]
Глядя на эти данные, мы знаем, что перед нами массив и в объектах присутствует другая информация. Мы можем легко сопоставить этот массив и создать динамический HTML-код в JavaScript. (В этой статье я буду немного схитрить: вместо использования createElement я буду использовать литералы шаблонов, просто чтобы немного ускорить работу.)
Но загвоздка с этими данными заключается в свойстве изображения. Давайте посмотрим это на коде:
JavaScript
const container = document.querySelector(".container") let element = `` data.map((item) => { const { id, name, username, image } = item console.log(image) let img = image[0].profile.url || `https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png` element += `<div class="card-container"> <img src=${img} alt=${name} /> <div class="details"> <span class="span-container"> ID: <p>${id}</p> </span> <span class="span-container"> Name: <p>${name}</p> </span> <span class="span-container"> Username: <p>${username || "unavailable"}</p> </span> </div> </div>` container.innerHTML = element })
В этом коде
- Мы выбрали контейнер из HTML.
2. Сопоставление данных.
3. Добавлен HTML к «элементу».
4. Добавлен последний «элемент» к «контейнеру».
Теперь посмотрим, какой результат мы получим:
Хм..!! Что-то здесь не так, у нас есть 3 объекта в нашем массиве данных, но отрисовано только 2. И у нас возникает ошибка, говорящая, что он не может найти какой-то URL. Поскольку мы знаем, что в данных присутствуют только URL-адреса изображений, а еще два уже отображаются на экране, это должен быть URL-адрес последнего пользователя Раушана, который отсутствует. И мы не смогли это отобразить.
Чтобы понять это, нам нужно сосредоточиться на этой части:
const { id, name, username, image } = item console.log(image) let img = image[0].profile.url || `https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png`
Мы деструктурировали элемент, чтобы получить свойства: id, имя, имя пользователя и изображение. Мы также могли бы использовать в динамическом html-коде item.id, item.name и т. д. Но мы деструктурировали его, чтобы сделать его немного быстрее.
Теперь URL-адрес изображения был вложенным, поэтому нам нужно было добраться до этого URL-адреса, чтобы его отобразить, и это то, что мы делаем с кодом «image[0].profile.url».
Затем мы просто присвоили это переменной «img» и использовали эту переменную в динамическом HTML для визуализации изображения.
Но если вы обратите пристальное внимание, мы используем другое изображение в качестве заполнителя, поэтому технически, если исходный URL-адрес изображения отсутствует, это должно отобразить изображение-заполнитель, верно?
Ответ: в данном случае этого не должно быть. Потому что изображение-заполнитель будет отображаться только тогда, когда оно сможет найти профиль изображения › [отсутствует URL-адрес]. Здесь, чтобы отобразить изображение-заполнитель, оно также должно иметь свойство профиля.
Как мы можем это исправить?
Я хочу сказать, что мы всегда можем увидеть и узнать, какова структура данных. Но мы никогда не можем быть уверены в том, какое свойство данных будет отсутствовать.
Поэтому нам нужен способ, с помощью которого мы могли бы эффективно проверять каждое свойство данных, и если оно отсутствует, мы отображаем значение по умолчанию. В противном случае мы столкнулись бы с той же ошибкой, что мы видели выше.
И чтобы сделать это возможным, необходимо добавить дополнительную цепочку.
Мы можем изменить код как таковой:
//old let img = image[0].profile.url || `https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png` //correct way (optional chaining) let img = (image[0] && image[0].profile && image[0].profile.url) || `https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png`
Этот код просто говорит:
if(image[0]){ //check for profile if(image[0].profile){ //check for url if(url){ //render the url } else{ //render the placeholder image } } else{ //render the placeholder image } } else{ //render the placeholder image }
Результат:
Это намного лучше и круче, не так ли? Мы можем сделать это в одной строке кода.
Хотя, если мы захотим, мы можем сделать этот однострочный код даже меньшим количеством символов:
Альтернативный синтаксис для необязательного связывания:
//optional chaining let img = (image[0] && image[0].profile && image[0].profile.url) || `https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png` //alternate syntax for optional chaining let img = image[0]?.profile?.url || `https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png`
Итак, это необязательная цепочка, которая сэкономит ваше время и поможет писать более эффективный код.