This media is not supported in your browser
VIEW IN TELEGRAM
Pattern matching
Pattern matching — это крутой концепт, который позволяет делать что либо в зависимости от совпадения с тем или иным шаблоном
Самой примитивной реализацией концепта в JavaScript можно считать объекты или конструкцию
Примерно то же самое можно реализовать и со
Есть такая библиотечка — ts-pattern. Она же позволяет отойти от примитивных примеров и использовать полноценный pattern matching, включая анализ вложенных структур и более сложные условия
На главной странице библиотечки есть очень наглядная гифка. Я предлагаю посмотреть на неё повнимательнее, описывать что-то дополнительно не вижу смысла
Скажу лишь то, что мне доводилось пользоваться этой библиотечкой и, как по мне, работает она шикарно. У меня остался исключительно положительный опыт)
Сам по себе концепт невероятно полезен для упрощения кода. Такой код проще читать, изменять и поддерживать. А в совокупности с
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
Pattern matching — это крутой концепт, который позволяет делать что либо в зависимости от совпадения с тем или иным шаблоном
В качестве шаблона может выступать какая-то константа или предикат
Самой примитивной реализацией концепта в JavaScript можно считать объекты или конструкцию
switch-case
:const statusIcon = {
warning: <WarningIcon />,
success: <SuccessIcon />,
error: <ErrorIcon />,
loading: <Spinner />
}
const status = "error"
const matched = statusIcon[status]
Примерно то же самое можно реализовать и со
switch-case
, но всё это не так интересноЕсть такая библиотечка — ts-pattern. Она же позволяет отойти от примитивных примеров и использовать полноценный pattern matching, включая анализ вложенных структур и более сложные условия
На главной странице библиотечки есть очень наглядная гифка. Я предлагаю посмотреть на неё повнимательнее, описывать что-то дополнительно не вижу смысла
Скажу лишь то, что мне доводилось пользоваться этой библиотечкой и, как по мне, работает она шикарно. У меня остался исключительно положительный опыт)
Сам по себе концепт невероятно полезен для упрощения кода. Такой код проще читать, изменять и поддерживать. А в совокупности с
ts-pattern
, решение будет ещё и типобезопасно, что также неоспоримый плюсСпасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
🔥24👍7❤3🐳3🤔1
Порталы в React
Сталкивались когда-нибудь с проблемой, когда нужно рендерить элемент за пределами текущей DOM-иерархии?
Для таких задач React предлагает решение — порталы
В документации реакта приведён такой код:
Работает этот код проще простого: элемент, переданный в функцию
Такой код будет работать, но он не очень удобен, поэтому многие компонентные библиотеки максимально упрощают порталы для разработчиков и делают подобные компоненты — они есть в Chakra UI, Material UI, Semantic UI и других либах
Если максимально упростить, то можно прийти к такому варианту:
Тут стоит уточнить две детали:
1. Мы создаём новый
Если мы будем рендерить контент сразу в
2. В
Тоже полезно, чтобы лишний раз не задумываться о том, как живёт портал и не создавать ненужных элементов в вёрстке
Да и всё. Тут компонент на 10 строчек буквально, ничего сверхъестественного. Если вам нужны порталы, то задумайтесь — скорее всего вам хватит такой простой реализации
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
Сталкивались когда-нибудь с проблемой, когда нужно рендерить элемент за пределами текущей DOM-иерархии?
Например, модальные окна, которые не должны быть вложены в основное дерево из-за проблем с позиционированием или всплывающие подсказки, которые всегда должны быть на переднем плане
Для таких задач React предлагает решение — порталы
В документации реакта приведён такой код:
import { createPortal } from 'react-dom';
<div>
<p>Текст расположен в родительском диве</p>
{createPortal(
<p>Текст расположен в document.body </p>,
document.body
)}
</div>
Работает этот код проще простого: элемент, переданный в функцию
createPortal
, будет маунтиться реактом не в родительский див, а в document.body
. Работать это будет с деревом любой вложенностиТакой код будет работать, но он не очень удобен, поэтому многие компонентные библиотеки максимально упрощают порталы для разработчиков и делают подобные компоненты — они есть в Chakra UI, Material UI, Semantic UI и других либах
Но, на самом деле, там нет ничего сложного
Если максимально упростить, то можно прийти к такому варианту:
const Portal = ({ children }: PropsWithChildren) => {
const [container] = useState(() => document.createElement('div'));
useLayoutEffect(() => {
document.body.appendChild(container);
return () => {
document.body.removeChild(container);
};
}, [container]);
return createPortal(children, container);
}
// ...
<Portal>
<p>Текст внутри портала</p>
</Portal>
Тут стоит уточнить две детали:
1. Мы создаём новый
div
внутри useState
, чтобы проще было контролировать порталЕсли мы будем рендерить контент сразу в
document.body
, то можно словить много проблем со стилями и отслеживанием самого порталаИспользуем мы именно useState, чтобы создавать элемент единожды и гарантировано на первый рендер компонента. Элемент создается внутри колбека инициализации состояния — он всегда вызывается единожды на маунт компонента
Как альтернатива, можно обойтись и рефом
2. В
useLayoutEffect
мы привязываем жизненный цикл тега-обёртки к циклу компонента порталаТоже полезно, чтобы лишний раз не задумываться о том, как живёт портал и не создавать ненужных элементов в вёрстке
useLayoutEffect используется вместо useEffect, чтобы обрабатывать портал без лишних мерцаний и более плавно
Вообще, тема разных эффектов и где какой использовать — это отдельная крупная тема, возможно сделаю об этом пост в будущем
Да и всё. Тут компонент на 10 строчек буквально, ничего сверхъестественного. Если вам нужны порталы, то задумайтесь — скорее всего вам хватит такой простой реализации
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
❤21👍11🐳3🔥1👏1
Составные компоненты
Есть такой паттерн для реакта, который называется Compound Components. Это можно перевести как "составные компоненты"
Запутались в словах? Лучше посмотреть в коде:
Вот пример прям из доки Ant Design:
Обратили внимание, как компоненты
Зачем же так сделали? Тут преследуется три цели:
1. Явно показать на уровне нейминга, что использовать
2. Расшарить общий контекст между всеми компонентами
3. Корректно стилизовать части
С неймингом и стилями, думаю, всё предельно ясно. Но что насчёт контекста? На самом деле,
В итоге получится, что все дочерние компоненты, пытающиеся получить доступ к контексту, без обёртки работать будут криво или и вовсе не будут
С точки зрения типов всё тоже не сложно. Тот же Ant Design делает так:
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #typescript #theory #code #react #patterns
Есть такой паттерн для реакта, который называется Compound Components. Это можно перевести как "составные компоненты"
Смысл этого паттерна заключается в том, что мы можем связать компоненты общим окружением и эффективнее использовать их вместе
То есть мы можем заранее объединить компоненты каким-то контекстом и переиспользовать их, например, через общее пространство имён, в качестве которого чаще всего выступает родительский компонент
Вот пример прям из доки Ant Design:
import { Layout } from 'antd';
<Layout>
<Layout.Header>Header</Layout.Header>
<Layout.Content>Content</Layout.Content>
<Layout.Footer>Footer</Layout.Footer>
</Layout>
Обратили внимание, как компоненты
Header
, Content
и Footer
мы получаем напрямую из компонента Layout
? Это и есть пример паттерна Compound Components. Компоненты связаны, а используются они из общего пространства — компонента Layout
Зачем же так сделали? Тут преследуется три цели:
1. Явно показать на уровне нейминга, что использовать
Layout.Footer
вне Layout
не нужно2. Расшарить общий контекст между всеми компонентами
Layout
3. Корректно стилизовать части
Layout
в зависимости от значения внутри общего контекстаС неймингом и стилями, думаю, всё предельно ясно. Но что насчёт контекста? На самом деле,
Layout
под собой содержит ещё и LayoutContext
, который содержит в себе состояние компонента Sider
и распространяет его на все дочерние компоненты. Схематически это выглядит примерно так:InternalLayout
└ LayoutContext <-- инициализируем контекст
├ Header
├ Content <-- а в этих компонентах получаем его значение
├ Footer
└ Sider
В итоге получится, что все дочерние компоненты, пытающиеся получить доступ к контексту, без обёртки работать будут криво или и вовсе не будут
С точки зрения типов всё тоже не сложно. Тот же Ant Design делает так:
import InternalLayout, { Content, Footer, Header } from './layout';
import Sider from './Sider';
// получаем тип базового layout компонента
type InternalLayoutType = typeof InternalLayout;
// создаём тип, который определит какие компоненты мы вложим в layout
type CompoundedComponent = InternalLayoutType & {
Header: typeof Header;
Footer: typeof Footer;
Content: typeof Content;
Sider: typeof Sider;
};
// нагло переприсваиваем тип
const Layout = InternalLayout as CompoundedComponent;
// нагло биндим нужные компоненты
Layout.Header = Header;
Layout.Footer = Footer;
Layout.Content = Content;
Layout.Sider = Sider;
// не менее нагло экспортируем как public-api
export default Layout;
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #typescript #theory #code #react #patterns
👍26❤8🔥5🐳3
Как скопировать значение в буфер обмена
Часто может возникнуть необходимость скопировать какое-то значение в буфер обмена, например, при нажатии на кнопку, и есть два способа сделать это:
Современный метод использует
Этот метод прост, но есть один важный нюанс: он работает только в безопасных контекстах (например, на страницах, загруженных по HTTPS). Проверить это можно с помощью флага
До появления
Комбинацией обоих способов можно покрыть абсолютно все кейсы во всех браузерах:
Спасибо за прочтение, это важно для меня❤️
@prog_way_blog — чат — #web #javascript #theory #data
Часто может возникнуть необходимость скопировать какое-то значение в буфер обмена, например, при нажатии на кнопку, и есть два способа сделать это:
Современный метод использует
navigator.clipboard
. Это браузерное API, которое предоставляет асинхронные методы для чтения и записи данных в буфер обменаnavigator.clipboard.writeText('Какой-то текст')
Этот метод прост, но есть один важный нюанс: он работает только в безопасных контекстах (например, на страницах, загруженных по HTTPS). Проверить это можно с помощью флага
window.isSecureContext
. Если страница не является безопасной, вызов методов из navigator.clipboard
вызовет ошибкуДо появления
navigator.clipboard
использовался метод document.execCommand('copy')
. Он требует немного больше манипуляций с DOM
, но работает в небезопасных контекстах и даже самых старых браузерах:// нужно создать какой-то текстовый элемент
// и установить ему необходимое значение
const textArea = document.createElement('textarea');
textArea.value = "Какой-то текст";
// убрать элемент куда-то далеко
textArea.style.position = 'absolute';
textArea.style.left = '-999999px;
// и добавить его в вёрстку
document.body.prepend(textArea);
// далее выделить наше поле ввода
textArea.select();
try {
// и скопировать значение в буфер обмена
document.execCommand('copy');
console.log('Текст скопирован!');
} catch (err) {
console.error('Не удалось скопировать текст: ', err);
}
// не забываем удалить элемент из вёрстки
textArea.remove()
Комбинацией обоих способов можно покрыть абсолютно все кейсы во всех браузерах:
if (navigator.clipboard && window.isSecureContext) {
// используем navigator.clipboard
} else {
// используем document.execCommand('copy')
}
Кратко:
— в современных браузерах используется браузерное API navigator.clipboard для взаимодействия с буфером
— в старых браузерах и на страницах, работающих по http, используется устаревший document.execCommand
Спасибо за прочтение, это важно для меня
@prog_way_blog — чат — #web #javascript #theory #data
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥38👍5🐳5❤4
Теги для шаблонных строк
В JavaScript есть, как по мне, крайне странный синтаксис. Самым очевидным его применением можно считать
В результате выполнения этого чуда мы получим компонент на основе нативного
Но вы когда нибудь задумывались, что
На самом деле, самый базовый пример такого синтаксиса можно рассмотреть так:
Всё, что делает эта функция — собирает строку из шаблона и подставленных переменных
—
—
Попробуем вызвать нашу функцию:
Использование обратных кавычек после именования функции вызывает эту самую функцию
По такому же принципу и работает
Этот синтаксис очень специфичный, ему не так много применений, но всё таки в некоторых случаях он бывает очень удобен. Например, в призме, с помощью такого такого синтаксиса можно кинуть запрос в БДшку
В реальной жизни вам скорее всего не понадобится писать подобные функции, но вдруг..
Спасибо за прочтение, это важно для меня❤️
@prog_way_blog — чат — #web #javascript #theory #data #code
В JavaScript есть, как по мне, крайне странный синтаксис. Самым очевидным его применением можно считать
styled-components
и выглядит всё это примерно так:const display = 'flex';
const Button = styled.button`
padding: 10px;
color: red;
display: ${display}
`
В результате выполнения этого чуда мы получим компонент на основе нативного
button
с предустановленными стилями из литераловНо вы когда нибудь задумывались, что
styled.button
— это тоже функция? А как она вызывается? Как устроена внутри?На самом деле, самый базовый пример такого синтаксиса можно рассмотреть так:
function foo(strings, ...values) {
let result = strings[0];
values.forEach((value, index) => {
result += value + strings[index + 1];
});
return result;
}
Всё, что делает эта функция — собирает строку из шаблона и подставленных переменных
—
strings
— массив строк, содержащий все части текста, разделенные переменными—
values
— массив значений, которые вставляются внутрь шаблонаПопробуем вызвать нашу функцию:
const name = "Денис"
const channel = "progway"
foo`Меня зовут ${name} и я люблю ${channel}`
Использование обратных кавычек после именования функции вызывает эту самую функцию
Для нашего примера, strings — это:
[
"Меня зовут ",
" и я люблю ",
""
]
а values:
[
"Денис",
"progway"
]
По такому же принципу и работает
styled-components
, конечно же, с более сложной логикой внутриЭтот синтаксис очень специфичный, ему не так много применений, но всё таки в некоторых случаях он бывает очень удобен. Например, в призме, с помощью такого такого синтаксиса можно кинуть запрос в БДшку
В реальной жизни вам скорее всего не понадобится писать подобные функции, но вдруг..
Спасибо за прочтение, это важно для меня
@prog_way_blog — чат — #web #javascript #theory #data #code
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21👍9❤8😐2🥰1🐳1
progway — программирование, IT
Теги для шаблонных строк В JavaScript есть, как по мне, крайне странный синтаксис. Самым очевидным его применением можно считать styled-components и выглядит всё это примерно так: const display = 'flex'; const Button = styled.button` padding: 10px; …
Ещё один пример
Бывает такое, что нужно встроить в строку значение, которое может быть пустым. Обычно пишутся доп. проверки:
Можно решить эту же задачу с помощью функции из поста выше, вот так это будет:
Просто вернем
Ну типа костыль. А вроде и нет. Просто ещё один пример посмотреть как это можно применить
@prog_way_blog — чат — #javascript #code
Бывает такое, что нужно встроить в строку значение, которое может быть пустым. Обычно пишутся доп. проверки:
const order = {
city: "Москва" // представим, что возможно undefined или null
}
const { city } = order
// могут писать что-то типа такой проверки
city ? `Ваш город: ${city}` : null
Можно решить эту же задачу с помощью функции из поста выше, вот так это будет:
type SubstitutionPrimitive = string | number | boolean | undefined | null;
const isNullOrUndefined = (value: SubstitutionPrimitive): value is undefined | null => {
return value === undefined || value === null;
};
const safePaste = (strings: TemplateStringsArray, ...substitutions: SubstitutionPrimitive[]) => {
let result = strings[0];
for (let index = 0; index < substitutions.length; index++) {
const value = substitutions[index];
if (isNullOrUndefined(value)) return null;
result += value + strings[index + 1];
}
return result;
};
Просто вернем
null
вместо строки, если какое либо из значений в подстановках null
или undefined
. Вот так это будет вызываться:const apple = {
name: 'Яблоко',
};
const orange = {};
safePaste`Товар: "${apple?.name}"`;
// Товар: "Яблоко"
safePaste`Товар: "${orange?.name}"`;
// null
Ну типа костыль. А вроде и нет. Просто ещё один пример посмотреть как это можно применить
@prog_way_blog — чат — #javascript #code
🔥14👍6❤4🐳4
Связываем React и localStorage через useSyncExternalStore
Как согласовать изменение состояния в реакте и поля в
Также можно обработать какое-то не-реактовое значение через комбинацию
Но не так давно в 18 версию
Многие скипнули его и даже не знают зачем он нужен, что, в целом, достаточно ожидаемо, ведь даже команда разработчиков позиционировала его больше как хук для разработчиков библиотек, а мы тут далеко не все пишем свои либы
Короче, что это за хук вообще? Очень просто — этот хук нужен для более глубокой интеграции внешних хранилищ в модель React. Говоря проще — хук нужен для того, чтобы триггерить рендер из внешних хранилищ, а не только через
Как раз этот хук и поможет нам интегрироваться с
На коленке код будет выглядеть примерно так:
В чём тут идея:
1. При вызове
2. В функции подписки
Использовать будем как обычный
Теперь хук при вызове с одним и тем же ключом к
Используя тот же подход, можно реализовать порой очень полезные хуки
Спасибо за прочтение, это важно для меня❤️
@prog_way_blog — чат — #web #javascript #theory #data #code #react
Как согласовать изменение состояния в реакте и поля в
localStorage
? До недавнего времени самым простым вариантом было создать контекст с внутренним React состоянием и обрабатывать всё взаимодействие с localStorage
через него — вариант рабочий, но далеко не идеален: легко напороться на ререндеры, много кода писать нужно ну и вот это вот всёТакже можно обработать какое-то не-реактовое значение через комбинацию
useState
+ useEffect
, но это ещё менее надёжно, ведь браузерные значения могут меняться и без уведомления реакта, и, соответственно, без ререндераКрасиво в одной из статей на хабре описали:
Для работы с состоянием в React используются хуки useState и useReducer, но они не умеют работать с состоянием, которое "живет" за пределами React, поскольку в один момент времени доступна только одна версия внешнего состояния.
Значения внешнего состояния могут меняться со временем без ведома React, что может приводить к таким проблемам, как отображение двух разных значений для одних и тех же данных.
Статья: https://habr.com/ru/companies/timeweb/articles/720136/
Но не так давно в 18 версию
React
добавили хук useSyncExternalStore
, который такую задачу решает намного изящнееМногие скипнули его и даже не знают зачем он нужен, что, в целом, достаточно ожидаемо, ведь даже команда разработчиков позиционировала его больше как хук для разработчиков библиотек, а мы тут далеко не все пишем свои либы
Короче, что это за хук вообще? Очень просто — этот хук нужен для более глубокой интеграции внешних хранилищ в модель React. Говоря проще — хук нужен для того, чтобы триггерить рендер из внешних хранилищ, а не только через
setState
функции Как раз этот хук и поможет нам интегрироваться с
localStorage
сильно проще и безопаснее. Тут localStorage
в понятие внешнего хранилища ложится просто шикарноНа коленке код будет выглядеть примерно так:
const useLocalStorageState = (key: string, defaultValue?: string) => {
const subscribe = (listener: () => void) => {
window.addEventListener("update-local-storage", listener);
return () => void window.removeEventListener("update-local-storage", listener);
};
const getSnapshot = () => localStorage.getItem(key) ?? defaultValue;
const store = useSyncExternalStore(subscribe, getSnapshot);
const updateStore = (newValue: string) => {
localStorage.setItem(key, newValue);
window.dispatchEvent(new StorageEvent("update-local-storage", { key, newValue }));
};
return [store, updateStore] as const;
};
В чём тут идея:
1. При вызове
updateStore
будем помимо изменения значения в localStorage
диспатчить на window
ещё и StorageEvent
с ключом, например, "update-local-storage"
2. В функции подписки
subscribe
объясним когда нужно вызывать getSnapshot
для получения актуального состояния из внешнего хранилища и когда от его прослушивания нужно отписаться. Можно воспринимать как эффектИспользовать будем как обычный
useState
:const [name, setName] = useLocalStorageState("name", "progway");
Теперь хук при вызове с одним и тем же ключом к
localStorage
(name
в примере выше) будет обновлять все зависимые компоненты при регистрации события "update-local-storage"
на window
Используя тот же подход, можно реализовать порой очень полезные хуки
useMediaQuery
, useWindowSize
и другие. О первых двух можно прочитать в статье от Timeweb CloudСпасибо за прочтение, это важно для меня
@prog_way_blog — чат — #web #javascript #theory #data #code #react
Please open Telegram to view this post
VIEW IN TELEGRAM
❤28👍11🔥6🐳2
Что такое Server-Sent Events
Часто
1. Нам нужно постоянно получать обновления с сервера
2. Не нужно постоянно отправлять что-то с клиента
Фикус в том, что держать
Для реализации понадобится только простенький эндпоинт на сервере, а далее процесс выглядит так:
1. Клиент делает
2. Сервер создаёт
3. Клиент подписывается на новое сообщение в стриме
На сервере это будет выглядеть примерно так:
На клиенте это будет выглядеть примерно так:
С таким кодом мы будем получать на клиенте сообщение "ПРИВЕТ!" каждую секунду
При этом, конечно же, никто не мешает усложнить логику со стороны сервера, и пушить новые сообщения в стрим не каждую секунду, а только при изменении данных
И конечно же никто не запрещает обернуть стрим в какой-нибудь React хук и сделать дженеричное решение для всего проекта/проектов
Если вы ни разу не работали SSE, то очень рекомендую потыкать хотя бы в песочнице — очень крутая штука!
Спасибо за прочтение, это важно для меня🥰
@prog_way_blog — чат — #theory #javascript #code #data #web
SSE
— это технология для однонаправленного соединения между сервером и клиентом, которая позволяет серверу отправлять обновления данных в реальном времениЧасто
SSE
могут стать отличной альтернативой WebSocket
. Он отлично подойдёт для кейсов, когда:1. Нам нужно постоянно получать обновления с сервера
2. Не нужно постоянно отправлять что-то с клиента
Такая односторонняя связь полезна при реализации:
— уведомлений
— обновления данных в реальном времени (цен, загрузки CPU...)
— индикатора прогресса загрузки большого файла
— даже в играх
И многих других случаях
Фикус в том, что держать
SSE
гораздо проще и дешевле, чем держать WebSocket
. Как по коду, так и по перфомансуДля реализации понадобится только простенький эндпоинт на сервере, а далее процесс выглядит так:
1. Клиент делает
GET
запрос на подготовленный эндпоинт через EventStream
2. Сервер создаёт
event-stream
, просто устанавливая нужный заголовок. Соединение не закрывается, и с этого момента сервер может пушить в стрим любые строковые данные3. Клиент подписывается на новое сообщение в стриме
На сервере это будет выглядеть примерно так:
const http = require('http');
http.createServer((req, res) => {
if (req.url === '/stream') {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
});
setInterval(() => {
res.write('data: ПРИВЕТ!\n\n');
}, 1000);
}
}).listen(3000);
На клиенте это будет выглядеть примерно так:
const source = EventSource('/stream')
sourse.addEventListener('message', (message) => {
console.log(message.data)
})
С таким кодом мы будем получать на клиенте сообщение "ПРИВЕТ!" каждую секунду
При этом, конечно же, никто не мешает усложнить логику со стороны сервера, и пушить новые сообщения в стрим не каждую секунду, а только при изменении данных
И конечно же никто не запрещает обернуть стрим в какой-нибудь React хук и сделать дженеричное решение для всего проекта/проектов
Если вы ни разу не работали SSE, то очень рекомендую потыкать хотя бы в песочнице — очень крутая штука!
Если кратко:
SSE — технология однонаправленной связи от сервера к клиенту
С помощью SSE можно обновлять данные на клиенте в рамках одного соединения в реальном времени
Спасибо за прочтение, это важно для меня
@prog_way_blog — чат — #theory #javascript #code #data #web
Please open Telegram to view this post
VIEW IN TELEGRAM
👍39❤13🔥7🐳3
Как реагировать на изменения объекта
В JavaScript обычные объекты не умеют уведомлять о своих изменениях, однако эту задачу можно решить с помощью
Ловушек много —
Например, можно переопределить поведение объекта при обращении к какому-нибудь из его свойств:
Но это лишь частный случай, можно сделать более утилитарный пример:
Сам
В первую очередь прокси удобен конечно же для создания реактивных систем, но также его можно применять, например, для валидации свойств и логирования
Удобно, что
Спасибо за прочтение, это важно для меня❤️
@prog_way_blog — чат — #theory #useful #javascript #code #web #patterns
В JavaScript обычные объекты не умеют уведомлять о своих изменениях, однако эту задачу можно решить с помощью
Proxy
Proxy
— это специальный встроенный в язык объект-обёртка, который позволяет изменить поведение других объектов, перехватывая действия над нимиnew Proxy(target, handlers)
создаёт прокси для объекта target
, где handler
содержит ловушки для перехвата операцийЛовушек много —
get
, set
, deleteProperty
, has
... (подробнее на MDN) — каждая из ловушек переопределяет реакцию объекта на взаимодействие с нимНапример, можно переопределить поведение объекта при обращении к какому-нибудь из его свойств:
const user = { name: "Денис", age: 23 };
const proxyUser = new Proxy(user, {
get(target, key) {
return key in target ? target[key] : "Не найдено";
}
});
proxyUser.name // "Денис"
proxyUser.city // "Не найдено"
Но это лишь частный случай, можно сделать более утилитарный пример:
const reactive = (obj, callback) => {
return new Proxy(obj, {
set(target, key, value) {
target[key] = value; // обновляем значение
callback(key, value); // вызываем реакцию
return true;
}
});
};
// Используем:
const state = reactive({ count: 0 }, (key, value) => {
console.log(`Свойство "${key}" изменилось:`, value);
});
state.count = 1; // Лог: "Свойство 'count' изменилось: 1"
state.count = 5; // Лог: "Свойство 'count' изменилось: 5"
Прикрутить сюда типы и рекурсивный вызов функции reactive на каждый вложенный объект и у вас почти получится свой vue.js🗿
Сам
Proxy
— это крайне нишевый инструмент, особенно в экосистеме реакта, где его встретить крайне сложно. Обычно можно обойтись более простыми вещами, но знать про прокси тоже нужно, может и пригодится. По крайней мере, у меня такой кейс на практике всё же былВ первую очередь прокси удобен конечно же для создания реактивных систем, но также его можно применять, например, для валидации свойств и логирования
Удобно, что
Proxy
крайне прост и к нему можно прикрутить что угодно. Например, к прокси можно прилепить zod
для валидации, как это сделано в zoxy. Тут вы ограничены лишь своей фантазиейЕсли кратко:
— Proxy — обёртка, которая позволяет переопределить реакцию на операцию для объекта
— Переопределение поведения происходит при помощи "ловушек"
Спасибо за прочтение, это важно для меня
@prog_way_blog — чат — #theory #useful #javascript #code #web #patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
❤28🔥15👍7🐳3🤓1
Как создать массив фиксированной длины?
На самом деле, способов множество. Можно создать простой массив пустых элементов:
Но тогда будет проблема с тем, чтобы его заполнить.
Решить её очень просто — можно просто заполнить массив через метод
Или мы можем попробовать вызвать метод
Пробуйте угадать что получится в ходе выполнения кода выше😂
А что будет, если вызвать вот такой код?
Ответ:ноль, потому что значений в массиве по сути то и нет. Поэтому и не работает
Поэтому если мы хотим использовать то придётся использовать вот такой хак :
Такая конструкция уже превратит разряженный массив в массив из сотни
Мой любимый способ, который я использую всегда в подобных кейсах:
Мне так привычнее и синтаксически наиболее понятно. Да и ещё фишка в том, что вторым аргументом в
Ну или прям совсем в лоб, про такое тоже не забываем:
Спасибо за прочтение, это важно для меня❤️
@prog_way_blog — чат — #web #javascript #theory #data
На самом деле, способов множество. Можно создать простой массив пустых элементов:
Array(100)
Но тогда будет проблема с тем, чтобы его заполнить.
Решить её очень просто — можно просто заполнить массив через метод
fill
:Array(100).fill(0)
Или мы можем попробовать вызвать метод
map
и заполнить массив индексами:Array(100).map((_, index) => index)
Пробуйте угадать что получится в ходе выполнения кода выше
Ответ:⬇️
Получится [empty × 100], а не массив индексов)
Тут дело в том, что при вызове Array(100) у нас изначально создаётся "разряженный" массив. Это когда под каждый элемент массива даже память не выделяется.
Язык просто создаёт пустую структуру с полем length в значении 100
А что будет, если вызвать вот такой код?
Object.keys(Array(100)).length
Ответ:
map
map
, [...Array(100)].map((_, index) => index)
Такая конструкция уже превратит разряженный массив в массив из сотни
undefined
и позволит вызвать map
Мой любимый способ, который я использую всегда в подобных кейсах:
Array.from({ length: 100 })
Мне так привычнее и синтаксически наиболее понятно. Да и ещё фишка в том, что вторым аргументом в
from
можно сразу передать функцию-маппер:Array.from({ length: 100 }, () => 'привет')
Ну или прям совсем в лоб, про такое тоже не забываем:
const array = []
for (let i = 0; i < 100; i++) {
array.push('progway')
}
Спасибо за прочтение, это важно для меня
@prog_way_blog — чат — #web #javascript #theory #data
Please open Telegram to view this post
VIEW IN TELEGRAM
👍35❤8🐳7👀3🤔1🗿1