M3 | WebDev
103 subscribers
105 photos
4 videos
14 links
Your guide to the world of programming 🌐🚀
Download Telegram
💡 preventDefault — как это работает?

Когда вы кликаете по ссылке или отправляете форму, браузер по умолчанию выполняет определённые действия. Например, переходит на другую страницу или перезагружает текущую. Но что, если вы хотите изменить это поведение? 🤔

👉 Метод event.preventDefault() останавливает стандартное действие браузера. Это полезно, если вы хотите реализовать свою логику при каком-либо событии.

Пример:
document.querySelector('a').addEventListener('click', (event) => {
event.preventDefault();
console.log('Клик перехвачен, но перехода не будет!');
});


🔥 Используйте preventDefault, чтобы:

• Сделать кастомную отправку формы через AJAX 📨
• Остановить переходы по ссылкам 📌
• Управлять кликами, свайпами и любыми действиями пользователя 🎮

Но не путайте с stopPropagation()! Этот метод блокирует всплытие событий, а preventDefault — только стандартное поведение.
Контекст провайдер в React: Что это и как его правильно использовать

Контекст провайдер (Context Provider) в React — это мощный инструмент для передачи данных через дерево компонентов, избегая необходимости явно передавать пропсы на каждом уровне. Это особенно полезно, когда данные, такие как тема, авторизация пользователя или настройки приложения, должны быть доступны во многих компонентах.

Что такое контекст в React?
Контекст позволяет создавать глобальные переменные для React-приложения. Он состоит из двух основных частей:

1. Контекст — создаётся с помощью React.createContext и служит хранилищем значений.
2. Провайдер (Provider) — оборачивает компоненты, которым необходимо передать значения.

Пример использования контекста
1. Создание контекста
import React, { createContext, useState } from 'react';

// Создаём контекст
export const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');

const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
};

return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};


2. Использование провайдера
Провайдер оборачивает компоненты, которые должны получать данные из контекста.
import React from 'react';
import { ThemeProvider } from './ThemeContext';
import App from './App';

const Root = () => (
<ThemeProvider>
<App />
</ThemeProvider>
);

export default Root;


3. Потребление контекста в дочерних компонентах
В дочерних компонентах доступ к данным осуществляется через useContext.
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';

const ThemeSwitcher = () => {
const { theme, toggleTheme } = useContext(ThemeContext);

return (
<div>
<p>Текущая тема: {theme}</p>
<button onClick={toggleTheme}>Сменить тему</button>
</div>
);
};

export default ThemeSwitcher;


Контекст провайдер в React — это мощный инструмент для управления состоянием на уровне приложения. Правильное использование контекста упрощает структуру кода и делает приложение более поддерживаемым. Однако всегда помните, что контекст — это не замена сложных менеджеров состояния, и его следует использовать с умом.
Как избежать ада ререндеров с контекстом в React?
Контекст в React передаёт значения всем дочерним компонентам, и любое изменение значения контекста вызывает ререндер всех потребителей (consumer). Это может существенно повлиять на производительность приложения, особенно если дерево компонентов большое.

Вот несколько стратегий, чтобы избежать "ада ререндеров":

1. Разделяйте контексты для разных данных
Если вы используете один контекст для хранения нескольких типов данных (например, тема, авторизация и настройки), то изменение любой из этих данных вызовет ререндер всех потребителей. Лучше создать отдельный контекст для каждой группы данных.

Пример:
// Тема
export const ThemeContext = createContext();

// Авторизация
export const AuthContext = createContext();

Это позволяет минимизировать область ререндеров, так как изменения в одном контексте не затрагивают другой.

2. Передавайте только необходимые данные
Чем больше данных в контексте, тем больше компонентов может быть затронуто ререндером. Старайтесь передавать только те данные, которые необходимы потребителям.

Плохо:
const UserContext = createContext({
user: { id: 1, name: 'Михаил', email: 'example@mail.com' },
updateUser: () => {},
});


Лучше:
const UserContext = createContext();
const UpdateUserContext = createContext();

Теперь компоненты, которым нужно только имя пользователя, не будут ререндериться при изменении функции updateUser.

3. Используйте мемоизацию контекстных значений
Если значение контекста вычисляется динамически, каждый ререндер провайдера будет пересоздавать объект или функцию, даже если данные не изменились. Это приводит к ререндерам потребителей.

Решение — использовать useMemo для мемоизации значения.

Пример:
import React, { createContext, useState, useMemo } from 'react';

export const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');

const value = useMemo(() => ({ theme, toggleTheme: () => setTheme((t) => (t === 'light' ? 'dark' : 'light')) }), [theme]);

return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
};

Теперь значение контекста обновляется только при изменении theme.

4. Потребляйте контекст там, где это необходимо
Избегайте использования useContext в компонентах, где данные контекста не нужны. Чем меньше компонентов напрямую потребляют контекст, тем меньше ререндеров.

Плохо:
const Parent = () => {
const { theme } = useContext(ThemeContext); // Используется только в дочернем компоненте
return <Child />;
};


Лучше:
const Parent = () => <Child />;

const Child = () => {
const { theme } = useContext(ThemeContext);
return <p>Тема: {theme}</p>;
};


5. Используйте селекторы контекста
Селекторы позволяют подписываться только на определённые части данных контекста. Для этого можно использовать кастомные хуки или библиотеки, такие как reselect-context.

Пример кастомного хука:
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) throw new Error('useTheme must be used within a ThemeProvider');
return context.theme;
};

export const useToggleTheme = () => {
const context = useContext(ThemeContext);
if (!context) throw new Error('useToggleTheme must be used within a ThemeProvider');
return context.toggleTheme;
};

Теперь можно подписываться только на theme или toggleTheme, а не на оба одновременно.

6. Используйте компонент React.memo
Если компонент использует контекст, но не должен ререндериться при его обновлении, можно обернуть его в React.memo.

Пример:
const ThemedComponent = React.memo(() => {
const { theme } = useContext(ThemeContext);
return <div>Текущая тема: {theme}</div>;
});


7. Подключение контекста через компонент-посредник
Если компоненту нужно только обновлять данные контекста, используйте специальный компонент, который изолирует изменения.
Пример:
const ThemeUpdater = () => {
const { toggleTheme } = useContext(ThemeContext);
return <button onClick={toggleTheme}>Сменить тему</button>;
};

Таким образом, ререндер затронет только ThemeUpdater, а не всю структуру.

Заключение
Чтобы избежать "ада ререндеров" при использовании контекста в React:

1. Разделяйте данные на несколько контекстов.
2. Используйте useMemo для мемоизации значений.
3. Подключайте контекст только в необходимых местах.
4. Используйте кастомные хуки и мемоизацию для работы с контекстом.

Применяя эти подходы, вы сможете эффективно управлять состоянием приложения и обеспечить высокую производительность.
🔍 Интересный JavaScript-кейс:
const obj = {
"1": "a",
1: "6",
[1]: "B"
};

console.log(obj["1"]);
💡 Что выведет этот код в консоль?
Anonymous Quiz
50%
a
14%
6
36%
B
💡 CSS-переменные — что это и зачем они нужны?

CSS-переменные (или custom properties) — это мощный инструмент, который позволяет задавать повторно используемые значения прямо в CSS. Они работают как переменные в JavaScript, но предназначены для стилей. 🎨

📌 Как задать CSS-переменную?
:root {
--main-color: #3498db;
--padding-size: 16px;
}


Переменные определяются в специальном синтаксисе --имя-переменной и обычно задаются в :root, чтобы они применялись глобально.

📌 Как использовать?
button {
background-color: var(--main-color);
padding: var(--padding-size);
}


С помощью функции var() можно подключать переменные в любых свойствах.

📌 Зачем это нужно?

1. 📋 Удобство: Меняете переменную — и обновляете дизайн сразу во всех местах.
2. 🎯 Темизация: Легко переключать темы (светлая/тёмная, брендовые цвета).
3. 🛠 Гибкость: Позволяют динамически изменять стили через JavaScript:
document.documentElement.style.setProperty('--main-color', '#e74c3c');


📌 Поддержка
CSS-переменные поддерживаются всеми современными браузерами (кроме IE 😅). Так что смело используйте!
🔥 Emits в Vue: Как правильно передавать события 🔥

Если вы работаете с компонентами Vue, вы наверняка сталкивались с ситуацией, когда нужно передать событие из дочернего компонента в родительский. Для этого используются emits.

Что такое emits?
emits — это способ декларации событий, которые компонент может отправлять. Это делает ваш код более предсказуемым, типизированным и удобным для отладки.

Пример использования:
Дочерний компонент:
<script setup>
import { defineEmits } from 'vue';

// Декларируем событие "submit"
const emit = defineEmits(['submit']);

function handleSubmit() {
emit('submit', { message: 'Данные отправлены!' });
}
</script>

<template>
<button @click="handleSubmit">Отправить</button>
</template>


Родительский компонент:
<script setup>
function onSubmit(payload) {
console.log(payload.message); // Данные отправлены!
}
</script>

<template>
<ChildComponent @submit="onSubmit" />
</template>


Почему это важно?
1️⃣ Ясность и предсказуемость: Выявление всех событий в одном месте (через defineEmits) упрощает понимание кода. Вы всегда знаете, какие события ожидаются.

2️⃣ Типизация событий: Если вы используете TypeScript, можно типизировать события:
<script setup lang="ts">
const emit = defineEmits<{
(event: 'submit', payload: { message: string }): void;
}>();
</script>


3️⃣ Снижение ошибок: Если вы попробуете отправить событие, не описанное в defineEmits, Vue выведет предупреждение в консоль.

📌 Совет: Используйте defineEmits вместе с defineProps, чтобы максимально упростить связь между компонентами.
Валидация на фронте
🚀 Скоро запуск аналитического крипто-проекта!

Готовлю платформу, которая поможет трейдерам получать актуальную информацию о рынке. В группу буду выкладывать детали разработки — проектирование и разработка сайта, ботов для Telegram, а также клиентской и серверной инфраструктуры. Всё это также можно будет смотреть в реальном времени на стримах в Twitch.

Подписывайтесь, чтобы следить за процессом: 👉 www.twitch.tv/m34r7
M3 | WebDev pinned a photo
🔄 Event Loop в JavaScript — как это работает?

JavaScript — однопоточный язык, но при этом он умеет обрабатывать асинхронные задачи. Как? За счёт Event Loop!

🚀 Как это работает?

1️⃣ Call Stack — выполняет код синхронно. Если функция завершилась, удаляем её из стека.

2️⃣ Web APIs — браузер обрабатывает асинхронные задачи (setTimeout, fetch, DOM события).

3️⃣ Queue — готовые к выполнению колбэки и промисы.

4️⃣ Event Loop — проверяет стек и очереди, двигая выполнение вперёд.

🔥 Что важно знать?

• Microtasks (промисы, MutationObserver) выполняются до рендеринга и перед setTimeout.
• setTimeout(0) не выполняется мгновенно — он ждёт очистки стека.
• async/await — это просто сахар над промисами и всё равно попадает в microtask queue.
🔼 Всплытие событий в JavaScript

Когда ты кликаешь по кнопке внутри div, почему срабатывает не только click на кнопке, но и на div? Это всплытие событий (Event Bubbling)!

🔥 Как это работает?
1️⃣ Событие сначала срабатывает на целевом элементе (куда кликнули).
2️⃣ Затем поднимается вверх по DOM-дереву (родитель, потом его родитель и так до document).

📌 Пример:
document.querySelector("div").addEventListener("click", () => {
console.log("Клик по div!");
});

document.querySelector("button").addEventListener("click", () => {
console.log("Клик по button!");
});


👉 Клик по button выведет:
Клик по button!
Клик по div!


Так как click сначала отработает на кнопке, а затем поднимется к div.

🛑 Как остановить всплытие?
Если не хочешь, чтобы событие всплывало:
event.stopPropagation();


⚡️ Полезно знать:
stopPropagation() остановит всплытие, но не предотвратит сам обработчик.
stopImmediatePropagation() ещё и заблокирует другие обработчики на этом же элементе.
Всплытие можно использовать, например, для делегирования событий (повесить click на общий контейнер вместо множества кнопок).