progway — программирование, IT
2.65K subscribers
25 photos
1 video
246 links
Чат: @prog_way_chat

Разборы вопросов и задач с собеседований, мысли, полезные материалы и просто вещи, что мне интересны из мира IT

Полезности и навигация в закрепе

По всем вопросам: @denisputnov
Download Telegram
Связываем React и localStorage через useSyncExternalStore

Как согласовать изменение состояния в реакте и поля в 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

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
👍3913🔥7🐳3
Как реагировать на изменения объекта

В 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