Эмулируем React useState в обычном JS (via data-attributes & css selectors)

от автора

Добрый день, Хабр! Решил поделиться своим небольшим, но полезным открытием в плане использования html data-attributes & css selectors.

Html data-attributes — это кастомные атрибуты, которые вы можете сами назначать куда-угодно и с каким угодно именем (но имя должно начинаться с префикса data-). Затем вы можете использовать их в css селекторах, чтобы влиять на содержимое классов и уже классами управлять элементами. Движок браузера автоматически среагирует на изменение data-атрибута и применит соответствующий код css класса.

Код реакт компоненты, где по нажатию кнопки что-то скрывается, что-то показывается:

import React, {useState} from "react";  const ComponentWithExpandableContent = () => {     const [expanded, setExpanded] = useState(false)      return <div style={{         display: 'flex',         flexFlow: 'column nowrap',         alignItems: 'start',         padding: 32,         gap: 32,     }}>          { !expanded && <div>Initial content</div> }          <button onClick={()=>setExpanded(!expanded)}>             { !expanded ? 'Expand' : 'Collapse' }         </button>          { expanded && <div>Additional content</div> }         { expanded && <div>More additional content</div> }      </div> } export default React.memo(ComponentWithExpandableContent)

Состояние expanded=false:

Состояние expanded=true:

Теперь просто html css js.

Файл emulating-use-state.html:

<!DOCTYPE html> <html lang="en"> <head>   <meta charset="UTF-8">   <title>     Эмулируем React useState в обычном JS      (via data-attributes & css selectors)   </title>   <link rel="stylesheet" type="text/css" href="emulating-use-state.css"> </head> <body>  <script>   function toggleExpand(){     const element = document.getElementById('component')     if (element.dataset.expanded!=='true'){       element.dataset.expanded = 'true'     } else {       element.dataset.expanded = 'false'     }   } </script>  <div class="someElementContext">   <!-- data-expanded хранит состояние -->   <div id="component" class="component" data-expanded="false">          <div class="collapsableContent">       <div>Initial content</div>     </div>          <button onClick="toggleExpand()">       <div class="collapsableContent">Expand</div>       <div class="expandableContent">Collapse</div>     </button>        <div class="expandableContent">       <div>Additional content</div>     </div>     <div class="expandableContent">       <div>More additional content</div>     </div>        </div> </div>  </body> </html>

Файл стилей emulating-use-state.scss:

.someElementContext {   display: contents;      .component {     display: flex;     flex-flow: column nowrap;     align-items: start;     padding: 32px;     gap: 32px;          // Классы, управляющие видимостью элементов на странице     // в зависимости от текущего значения data-expanded     .expandableContent {       display: none;     }     .collapsableContent {       display: contents;     }     &[data-expanded=true] .expandableContent {       display: contents;     }     &[data-expanded=true] .collapsableContent {       display: none;     }   } }

Сгенерированный средой разработки emulating-use-state.css:

.someElementContext {   display: contents; } .someElementContext .component {   display: flex;   flex-flow: column nowrap;   align-items: start;   padding: 32px;   gap: 32px; } .someElementContext .component .expandableContent {   display: none; } .someElementContext .component .collapsableContent {   display: contents; } .someElementContext .component[data-expanded=true] .expandableContent {   display: contents; } .someElementContext .component[data-expanded=true] .collapsableContent {   display: none; }

Получилось поведение аналогичное описанному в реакт компоненте.

Здесь в качестве стэйта выступает кастомный data-атрибут data-expanded — он и хранит состояние. А css селектор [data-expanded=true] изменяет свойство display из none в contents (display: contents означает показывать содержимое элемента так, как будто самого элемента не существует) и обратно в специальных классах-обёртках .expandableContent & .collapsableContent, которыми можно просто обернуть любые элементы в html разметке.


ссылка на оригинал статьи https://habr.com/ru/post/708822/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *