DevGang
Авторизоваться

Создание раскрывающегося меню в React: пошаговое руководство

В этой статье я продолжу освещать концепции React, которые я изучаю посредством парного программирования с искусственным интеллектом для создания веб-сайта Асоки по «Звездным войнам».

В этой статье основное внимание будет уделено созданию «выпадающего меню». Продолжая использовать лучшие практики кодирования, я создаю компоненты Menu и Navbar, чтобы выпадающее меню работало. Кроме того, чтобы сохранить код максимально чистым, я также буду использовать дополнительные пользовательские компоненты и функцию сопоставления.

Изначально все кнопки категорий «Звездные войны», необходимые для раскрывающегося меню, были закодированы для работы непосредственно в основном jsx-файле приложения. Итак, когда я впервые попытался создать отдельный компонент меню, мое приложение сломалось!

С помощью моего помощника по искусственному интеллекту Рикса я успешно создал работающий компонент меню с раскрывающимся списком, размещенным внутри компонента панели навигации!

Предпосылки

Основываясь на серии статей о создании веб-сайта «Star Wars Ahsoka React», понимание создания выпадающего меню требует знакомства с определенными концепциями. Пожалуйста, обратитесь к моим предыдущим статьям, чтобы понять используемые пользовательские компоненты и функции.

Предварительные условия для создания раскрывающегося меню включают в себя:

  1. Знакомство с компонентами StarWarsCard, SmallCardContent и LargeCardContent.
  2. Понимание функции MapItems, используемой для создания нескольких компонентов.

Серия статей:

Создание компонента Menu

Моя первая попытка создать компонент Menu не удалась.

Меню, содержащее все кнопки категорий, в главном приложении работало как положено. Однако код казался громоздким, и я знал, что лучше создать его как отдельный компонент.

Как работают кнопки категорий, когда пользователь нажимает кнопку категории меню:

  • Отображаются новые небольшие компоненты карт Star Wars выбранной категории.
  • Первый элемент в выбранной категории устанавливается как выбранный элемент.
  • Большой компонент карты Star Wars отображается вместе с соответствующим выбранным элементом.

Сложными частями кнопок меню являются анонимные функции стрелок, переменные useState и ловушка useEffect, которые необходимы для их правильной работы. Итак, у меня было ощущение, что рефакторинг будет трудным.

Проблема: кнопки меню напрямую управляют состоянием основного компонента приложения. Итак, когда я попытался переместить их в отдельный компонент, они потеряли доступ к необходимым переменным состояния и функциям обновления состояния.

Итак, мой первый рефакторинг сработал, когда я правильно передал все необходимые значения в качестве реквизита! Но знаете что? Это оказалось такое же количество строк громоздкого кода! Я также импортировал символы как в основные компоненты App, так и в Menu, чтобы они работали должным образом. Итак, пришло время провести дальнейший рефакторинг кода.

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

Переменные useState

Чтобы кнопки меню работали должным образом в отдельном компоненте, переменные useState должны быть объявлены в основном приложении, а затем переданы в качестве реквизита предлагаемому компоненту меню.

Создал переменную для всех категорий

const [selectedCategory, setSelectedCategory] = useState(characters);  
const categories = { characters, creatures, droids, locations, organizations, vehicles, weapons_and_tech };

С помощью этого переработанного кода нам просто нужно передать два реквизита компоненту Menu.

<Menu 
   setSelectedCategory={setSelectedCategory} 
   categories={categories}
/>

Вот пример того, что содержит файл данных:

// Droids
import hk_87_assassin_droid from './images/droids/hk-87-assassin-droid.jpeg';
import star_navigator_droid from './images/droids/star-navigator-droid.jpeg';

const droids = [
    {
        name: 'HK-87 ASSASSIN DROID',
        image: hk_87_assassin_droid,
        about: 'Assassins by design, the HK-87 droids loyal to Morgan Elsbeth have serve her as tireless bodyguards and enforcers.',
    }, 
    {
        name: 'STAR NAVIGATOR DROID',
        image: star_navigator_droid,
        about: 'With programmed navigation skills and efficiency, the Star Navigator droids carry out the orders of Morgan Elsbeth as she brings her plans to fruition.',
    }                   
]
**СОВЕТ:** Присвоение изображений переменным помогает предотвратить неприятные ошибки сборки или транспиляции!

Хук useEffect

Чтобы компонент Menu продолжал работать должным образом, перехват useEffect должен оставаться в основном приложении.

Перехватчик отслеживает изменения в переменной selectedCategorystate. Всякий раз, когда selectedCategory изменяется, перехватчик запускает функцию, которая устанавливает selectedItem в первый элемент в новой категории. Без этого крючка в основном приложении selectedItem не будет обновляться при изменении категории, и компонент меню не будет работать правильно.

  useEffect(()=>{
    setSelectedItem(selectedCategory[0]);
  },[selectedCategory])

Компонент Menu

С помощью моего AI-помощника Рикса мы создали новый улучшенный компонент Menu!

export default function Menu({ setSelectedCategory, categories }) {
    return (
        <menu>
            {Object.keys(categories).map(category => (
                <button key={category} onClick={() => setSelectedCategory(categories[category])}>
                    {category.charAt(0).toUpperCase() + category.slice(1)}
                </button>
            ))}            
        </menu>
    )
}

Здесь есть много концепций кодирования, так что давайте потратим некоторое время, чтобы их распаковать! (мне даже потребовалось время, чтобы это осознать!

Функция Menu

Начнем с первой строки нашего компонента Menu: export default function Menu({ setSelectedCategory, categories }). Эта строка определяет функциональный компонент в React под названием Menu. Часть export default означает, что этот компонент Menu экспортируется для использования в других файлах. Он принимает два реквизита — setSelectedCategory, функцию, и категории, объект, которые передаются из основного приложения.

Object.keys

Чтобы понять, как работает компонент Menu, нам нужно сначала понять, как работает Object.keys.

Object.keys — это метод в JavaScript, который возвращает массив имен собственных перечислимых свойств данного объекта. По сути, он предоставляет способ получить массив ключей из объекта. Это полезно, когда вы хотите перебрать ключи объекта или когда вы хотите создать новый массив на основе ключей объекта.

Вот недостающая информация, которая мне нужна, чтобы понять, как **Object.keys** работает в этом компоненте: понимание сокращенного синтаксиса! (Я был сбит с толку, потому что мой массив объектов не содержал пар ключ-значение.)

Объект categories, который я определил, использует сокращенный синтаксис имени свойства в JavaScript. Это особенность ES6, где вы можете напрямую использовать переменные в качестве свойств объекта. Когда вы определяете объект, подобный этому:

const categories = { characters, creatures, droids, locations, organizations, vehicles, weapons_and_tech };

Это эквивалентно этому:

const categories = { 
    characters: characters, 
    creatures: creatures, 
    droids: droids, 
    locations: locations, 
    organizations: organizations, 
    vehicles: vehicles, 
    weapons_and_tech: weapons_and_tech 
};

В этом случае переменные characters, creatures, droids, locations, organizations, vehicles, weapons_and_techare являются ключами объекта categories, а соответствующие им значения являются значениями этих переменных.

.map(category)

Затем мы используем метод map для перебора этого массива. Для каждого элемента массива (который является именем категории) мы создаем элемент button. В key свойстве кнопки указано имя категории, а в свойстве onClick задана функция, которая обновляет состояние selectedCategory в родительском компоненте соответствующей категорией из объекта categories.

<button key={category} onClick={() => setSelectedCategory(categories[category])}>

Названия кнопок

Теперь давайте обсудим строку {category.charAt(0).toUpperCase() +category.slice(1)}. Эта строка кода отвечает за именование кнопок. Он принимает имя категории, делает первую букву заглавной и оставляет остальную часть строки как есть.

 {category.charAt(0).toUpperCase() + category.slice(1)}

Окончательная версия этого компонента меню представляет собой оптимизированную функцию многократного использования, которая позволяет легко добавлять или удалять категории для создания соответствующих кнопок!

Создание выпадающего меню

Теперь, когда мы создали полнофункциональный компонент меню, пришло время поработать над dropdown меню!

Вот готовое выпадающее меню:

Как упоминалось ранее, все кнопки категории Star Wars изначально были закодированы и отрисованы непосредственно в главном jsx-файле приложения:

Компонент Navbar

Теперь, когда у нас есть работающий компонент Menu, пришло время создать компонент Navbar, который его использует!

Компонент Navbar будет содержать два логотипа Star Wars и несколько кнопок меню. На данный момент мы сосредоточимся только на одной кнопке меню под названием «DATABANK», которая содержит все категории Star Wars для нашего раскрывающегося меню.

Импорт зависимостей и компонентов

Для компонента Navbar мы импортируем useState React, два файла изображений Star Wars и вновь созданный компонент Menu.

import { useState } from 'react';
import star_wars_logo from '../images/miscellaneous/star-wars-logo.png';
import ahsoka_logo from '../images/miscellaneous/ahsoka-logo.png';
import Menu from './Menu';

Функция навигационной панели

Функция Navbar принимает два реквизита: categories и setSelectedCategory. Category prop — это объект, который содержит все различные категории данных Star Wars. Свойство setSelectedCategory — это функция, которая обновляет состояние выбранной категории Star Wars в родительском компоненте. (Мы будем писать весь код внутри этой функции.)

function Navbar ({ categories, setSelectedCategory }) {

}

Объявление переменной состояния

В функции Navbar useState используется для объявления переменной состояния isDatabankVisible. Первоначально для этой переменной состояния установлено значение false, что указывает на то, что раскрывающееся меню не отображается. Перехватчик useState возвращает два значения: текущее состояние (isDatabankVisible) и функцию для его обновления (setIsDatabankVisible). Эта переменная состояния используется для управления видимостью раскрывающегося меню. Если isDatabankVisible имеет значение true, отображается раскрывающееся меню; если оно false, раскрывающееся меню скрыто.

const [isDatabankVisible, setDatabankVisible] = useState(false);

Функция навигационной панели

Функция Navbar возвращает блок JSX, который формирует структуру панели навигации. Он включает в себя два элемента img и div, в котором находится кнопка «DATABANK» и раскрывающееся меню. (Я использую Flexbox для стилизации содержимого навигационной панели.)

    return (
        <nav>
            <div className='flex-col'>
            <img src={star_wars_logo} className='logo' /><img src={ahsoka_logo} className='logo ahsoka'  />
            <div className='flex ctn-navbar'>
                {/* buttons and the dropdown menu go here*/}
            </div>
            </div>
        </nav>
    )

Кнопки Navbar

Я создал контейнер div, в котором будут храниться все кнопки навигации, и применил к нему макет flexbox для упрощения их расположения. Внутри этого контейнера я создал четыре отдельных элемента div, каждый из которых представляет кнопку на панели навигации. Эти кнопки имеют названия «NEWS», «FEATURES», «VIDEO» и «DATABANK». Текст внутри каждого div — это то, что вы увидите на каждой кнопке.

<div className='flex ctn-navbar'>
     <div className="navbar-buttons">NEWS</div>
     <div className="navbar-buttons">FEATURES</div>
     <div className="navbar-buttons">VIDEO</div>
     <div className="navbar-buttons">DATABANK</div>
</div>

Кнопка DATABANK:

Кнопка DATABANK будет включать все категории Star Wars в нашем раскрывающемся меню. С этой кнопкой связаны два обработчика событий: onMouseEnter и onMouseLeave. Эти события запускаются, когда указатель мыши входит или покидает область кнопки соответственно.

OnMouseEnter связан с функцией, которая устанавливает для isDatabankVisiblestate значение true. Это действие делает раскрывающееся меню видимым путем обновления состояния. И наоборот, onMouseLeave связан с функцией, которая устанавливает для isDatabankVisible значение false, скрывая раскрывающееся меню, как только указатель мыши покидает область кнопки.

<div className="navbar-buttons" onMouseEnter={() => setDatabankVisible(true)} onMouseLeave={() => setDatabankVisible(false)}>
    DATABANK
    {isDatabankVisible && (
        <div className="dropdown-menu">
            <Menu setSelectedCategory={setSelectedCategory} categories={categories}/>
        </div>
    )}
</div>

Выпадающее меню

Раскрывающееся меню отображается условно на основе значения isDatabankVisiblestate. Если isDatabankVisible имеет значение true, компонент Menu отображается; если оно false, компонент Menu не отображается, эффективно скрывая раскрывающееся меню.

Этот условный рендеринг происходит в коде JSX компонента Navbar, в частности в div для кнопки DATABANK. Когда компонент Menu визуализируется, ему передаются два реквизита: categories и setSelectedCategory. Эти реквизиты позволяют компоненту Menu отображать кнопки категорий и обновлять выбранную категорию при нажатии кнопки.

Итак, поскольку вся «тяжелая работа» была проделана при создании компонента Menu все, что нам нужно сделать, это использовать его для отображения полнофункционального раскрывающегося меню.

Выпадающее меню CSS

Вот код CSS, относящийся к раскрывающемуся меню, обсуждаемому в статье:

nav {
  background-color: black;
  color: white;
  height: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 25px;
  font-weight: bolder;
}

button {
  margin: 3px;
  padding: 0;
  width: 100%;
  background-color: black;
  color: white;
  font-weight: bold;
}

button:hover,
button:focus {
  background-color: white;
  color: black;
}

.navbar-buttons {
  border: 1px solid lightgray;
  position: relative;
  padding: 5px;
  font-size: 12px;
  font-weight: bold;
  color: lightgray;
  margin: 0 5px;
}

.navbar-buttons:hover,
.navbar-buttons:focus {
  border: 1px solid white;
  color: black;
  background: white;
  cursor: pointer;
  box-shadow: 0 0 10px goldenrod, 0 0 5px goldenrod, 0 0 3px goldenrod, 0 0 1px goldenrod;
}

.dropdown-menu {
  position: absolute;
  margin-top: 6px;
  margin-left: -25px;
  padding: 8px;
  color: white;
  background-color: black;
  width: 130px;
  z-index: 1;
  flex-direction: column;
  align-items: flex-end;
  display: flex;
}

Этот блок кода охватывает стиль кнопки раскрывающегося списка и самого раскрывающегося меню. Он включает стили для нормального состояния кнопки, а также состояний ее наведения и фокуса. Здесь также определяются положение, размер, цвет и другие свойства макета раскрывающегося меню.

Проект на данный момент

Вот ссылки на проект:

  1. GitHub repo
  2. Netlify deployed project

Вывод

В этой части серии, посвященной созданию веб-сайта Star Wars Ahsoka React с помощью помощника по искусственному интеллекту, я успешно разработал выпадающее меню - важный навык программирования, имеющий отношение к разработке веб-сайтов.

Однако создание выпадающего меню сопряжено с многочисленными трудностями. Чтобы соответствовать лучшим практикам кодирования, я создал компоненты Menu и Navbar, которые усложнили процесс.

Изначально моя попытка переместить необходимые кнопки категорий для выпадающего меню в отдельный компонент потерпела неудачу. Однако, после понимания и правильной реализации использования props для передачи необходимых переменных состояния и функций и определения того, где находится требуемый хук useEffect, мне удалось создать функциональный отдельный компонент Menu.

Но на этом путешествие не закончилось. Я сделал еще один шаг вперед, создав компонент Navbar, в котором находится компонент Menu, в конечном итоге создав желаемую функцию выпадающего меню, сохранив при этом чистоту кода! Этот процесс также включал понимание и реализацию условного рендеринга на основе переменных состояния и лучшее понимание того, как работают функции отображения.

С помощью моего помощника по искусственному интеллекту Rix я смог провести рефакторинг кода в рамках проекта и создать единую переменную для всех категорий, что упростило процесс передачи реквизитов компоненту меню, что привело к более чистой и оптимизированной базе кода.

Этот опыт научил меня тому, что, хотя создание сложных функций поначалу может показаться пугающим, любую проблему с кодированием можно преодолеть с помощью настойчивости, правильных стратегий и готовности к рефакторингу и улучшению. Самое главное, понимание того, как работает код, и принципов кодирования, лежащих в его основе, имеет первостепенное значение!

Поскольку я продолжаю свой путь в изучении и внедрении лучших практик программирования, я приглашаю вас присоединиться ко мне. Помните, лучший способ учиться - это делать. Итак, не бойтесь экспериментировать, проводить рефакторинг и даже ломать код в своих проектах. Все это часть процесса обучения!

Источник:

#JavaScript #React
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу