>> Единственное, чего не понял, это как в стили запихать это: display: citiesOpened ? 'block' : 'none',
>> Как думаешь, чего следующее ковырять?
Сейчас я поправлю нейминг в стилях и попробуй тогда вынести в отдельный компонент DropdownMenu, чтобы в нем уже были как положено interfaces.ts и styles.ts, и чтобы его можно было импортировать в меню. Очень хорошая задачка.
Всем привет!
Поступил свежий вопрос, в ответ на который и пишу данный топик. Задачка довольно тривиальная, но в реализации показывает преимущество использование styled-components в связке с TypeScript.
Что было и что стало?
Что здесь не так?
1. На уровне TS здесь никак не задается, что свойство style::display обязательное.
2. Лишняя заморочка с придумыванием className, чтобы оно точно не пересеклось с какими-нибудь другими стилями (Вдруг где-то еще прописаны стили для .dropdown-menu).
3. Навозможность переиспользования кода (где-то же еще может понадобиться такое меню (хотя для этого в таком виде все равно его надо улучшать, но это уже другая история:)))
Что сделано.
На всякий случай весь коммит: https://github.com/Pivkarta/pivkarta.ru-2/pull/2/commits/0277ad2d148046b519a1c6c11923385423868628
Простые HTML-теги были заменены на styled-components.
Корневой li на вот это:
А ul на вот это
Соответственно в самом реакт-компоненте стало так:
В чем здесь выигрыш?
1. TS будет ругаться, если обязательное свойство не указано.
2. Не надо придумывать className. Здесь мы оперируем самими компонентами и их же можно использовать для расширения стилей. Пример:
Здесь я специально так сделал для наглядности, хотя в нашем случае это и не требовалось. В общем, в самом DropdownMenu указана максимальная высота 60vh, но в MainMenuStyled прописано, что вложенным компонентам DropdownMenu надо задать максимальную высоту 70vh. При этом вполне допускается и другие классические селекторы прописывать типа class, id и т.п. К примеру так:
А в реакт-компоненте прописать этот класс:
3. Теперь это меню можно вынести в самостоятельный реакт-компонент и использовать его в других местах, при этом легко переопределять стили.
P.S. Я только тут свои же правила нейминга нарушил. В стилях такие компоненты надо писать с суффиксом Styled, то есть не DropdownMenu, а DropdownMenuStyled. Но это я сейчас отдельно коммит выкачу, статью уже не буду переписывать. Просто имейте это ввиду.
Амен)
Спасибо!
Как думаешь, чего следующее ковырять?
В целом ты все верно описал, но вот это:
>> А вот это что законструкция?
return () => { ... }
Как раз и выдает твою ошибку: ты объявление функции воспринимаешь буквально как уже выполнение функции, а это совсем не так. Функция выполняется только когда ее вызывают. До вызова все то, что описано в теле этой функции, не выполняется и никакого значения не имеет.
Если точнее, то скорее всего ты это понимаешь, но все же надо правильно говорить и в предложении, где есть объявление функций и вызов их, так и говорить "объявляем", "вызывает" (или "вызывает", если явно хочешь указать на того, кто вызывает (окно, документ, ссылка)).
return () => {...} в хуке useEffect - это возвращаемая не обязательная функция, которая выполняется каждый раз при ререндеринге этого компонента (при изменении стейста и пропсов). Только важно учитывать второй параметр - deps. В твоем случае это [citiesOpened]. То есть этот хук будет перевыполняться только если меняется переменная citiesOpened (Речь о повторном вызове. В первый раз обязательно хук выполнится).
Так вот, эта возвращаемая функция выполняется перед повторным выполнением и размонтированием компонента (то есть при удалении из DOM). Тут несколько сложно, но со временем поймешь. Коротко можно только сказать так: при срабатывании хука навешивается ивент на документ, а когда хук удаляется, то выполняется этот возвращаемый метод (если он прописан в хуке). В нашем случае он нужен для того, чтобы снять наш слушатель с документа. А иначе сколько раз раз выполнится хук, столько и событий навесится на документ, и они скорее всего все будут не актуальны. Это вызовет утечку памяти.
В общем, твоя задача в рамках этих небольших заданий научиться понимать все в рамках этих заданий. Если что-то не понятно, обязательно спрашивай. Дьявол кроется в мелочах.
Попробую описать:
Если citiesOpened==false, то ничего не делаем.
Иначе - создаём функцию closeCitiesOpenedEvent , которая сеттеру citiesOpenedSetter назначает false.
Слушатель window.document.addEventListener('click', closeCitiesOpenedEvent) ждет клика на докуументе, чтобы запустить closeCitiesOpenedEvent.
window.document.removeEventListener('click', closeCitiesOpenedEvent) - обнуляем слушателя.
А вот это что законструкция?
return () => { ... }
Пока я делаю, вопрос: ты вот здесь точно все понимаешь? Каждую конструкцию? https://github.com/Pivkarta/pivkarta.ru-2/blob/f658013e24f93ae1605b6eeb16296785036ea2c6/src/pages/_App/Layout/MainMenu/index.tsx#L46-L60
Есть: https://github.com/Pivkarta/pivkarta.ru-2/commit/f658013e24f93ae1605b6eeb16296785036ea2c6
Единственное, чего не понял, это как в стили запихать это: display: citiesOpened ? 'block' : 'none',
Понял, правлю)
Технически работает. Но результат надо улучшить.
1. Избавиться от style={...}, перенести стили в styles.ts
2. Навесить на document обработчик, чтобы по клику меню закрывалось. А то сейчас только по клику в сам корневой пункт меню.
Вроде сделаал: https://github.com/Pivkarta/pivkarta.ru-2/commit/e577598920a90afe36aff5b9a6b024b77b9407ef
Посмотришь?