Перейти к содержанию

Юрий Бондаренко

Fullstack-разработчик с 20-летним стажем в веб-разработке, специализируюсь на экосистеме React.

 Github      GetMentor      Boosty      Linkedin      Резюме

Стафф

  • Доки


    HTML+CSS
    Typescript
    Angular
    React
    React Native
    PWA
    NodeJS
    XSLT

  • Фуфломицины


    Приложения для проверки псевдо-лекарств

    PWA
    Android
    Github

  • Игральные кубики


    Приложения для бросков игральных костей

    Android
    PWA
    Github

  • Duckov.ru


    Русскоязычная база знаний по игре Escape from Duckov

    Сайт
    Youtube
    Tg канал

  • Opennext Cloudflare PWA


    Приложение для демонстрации работы возможностей PWA-приложений на базе фреймворка OpenNext и воркеров Cloudflare

    PWA
    Github

  • use-server-sent-event


    NPM-пакет, предоставляющий простой и эффективный React hook для обработки Server-Sent Events (SSE)

    NPM
    Github

Переводы интересного

Депрекация React-компонента с помощью перегрузок TypeScript

Важное замечание

Учтите, что решение из этой статьи закрывает очень конкретную проблему и ситуацию. Это не рекомендуемый способ поддерживать версии компонентов внутри проекта.

Что за ситуация?

Представим, что у вас есть монорепозиторий, а внутри него пакет с общими компонентами, которые используют разные приложения. Все потребители подключают этот пакет через workspace:^. Поскольку пакет с компонентами не публикуется в registry, разрешение версии на этапе публикации здесь не важно: workspace:^ просто означает, что каждый пакет в монорепозитории, который от него зависит, всегда получает текущую локальную реализацию — живую версию, а не снимок из registry.

Но что произойдет, если вы захотите внести breaking change в компонент: например, изменить у Card радиус скругления, цвет фона заголовка и тень? Это значит, что все потребители потенциально могут сломаться, верно?

Кто-то может предложить создать новый компонент, а старый пометить как deprecated. Но тогда всем потребителям придется менять имя используемого компонента. Кроме того, у вас появятся два разных компонента в двух разных директориях (если вы хорошо организуете код), а это создает еще больше шума.

Мне хотелось чего-то более простого и устойчивого. Цели были такие:

  • Сохранить то же имя компонента
  • Видеть, что именно устарело
  • Иметь простой способ переключаться между старой и новой версиями

Один из способов сделать это

В TypeScript, как и в некоторых других языках вроде Java, есть полезная концепция перегрузок. Перегрузка означает, что у вас может быть одно и то же имя, например для функции, но при вызове с разными аргументами вы получаете разную реализацию. А React-компоненты, как мы знаем, по сути являются функциями. Отлично.

Допустим, у меня есть очень простой компонент Card:

import React from 'react';
import './index.scss';

export interface CardProps {
    title: string;
    content: string;
    style?: React.CSSProperties;
}

const Card = ({ title, content, style }: CardProps) => {
    return (
        <div className="card" style={style}>
            <div className="card-header">
                <span className="card-title">{title}</span>
            </div>
            <div className="card-content">{content}</div>
        </div>
    );
};

export default Card;

Он выглядит так:

Component Card

Но я хочу создать новую версию компонента Card, у которой будут другие радиус скругления, цвет фона заголовка и тень, а старую версию пометить как deprecated.

Для функции Card можно создать перегрузку. Посмотрим как.

Сначала я создал новый интерфейс для пропсов новой карточки. В нем есть единственный проп new, который всегда равен true. Чуть позже посмотрим, как он используется.

(Можно пойти дальше и завести v1, если вы планируете поддерживать больше одной версии, но, пожалуйста, не делайте так: этот подход не заменяет версионирование пакетов.)

1
2
3
export interface NewCardProps extends CardProps {
    new: true;
}

Затем назовем старую функцию Card как LegacyCard, а новую версию — NewCard. В NewCard мы внесем все breaking changes, которые хотели.

function LegacyCard({ title, content, style }: CardProps): React.JSX.Element {
    return (
        <div className="card" style={style}>
            <div className="card-header">
                <span className="card-title">{title}</span>
            </div>
            <div className="card-content">{content}</div>
        </div>
    );
}

const NewCard = ({ title, content, style }: CardProps) => {
    return (
        <div className="card card-new" style={style}>
            <div className="card-header">
                <span className="card-title">{title}</span>
            </div>
            <div className="card-content">{content}</div>
        </div>
    );
};

Теперь интересная часть — перегрузка:

Обратите внимание, что у нас есть три определения функции Card: одно для старой версии, одно для новой и одно для самой перегрузки. Также заметьте, что вариант со старыми CardProps помечен как @deprecated.

/* eslint-disable no-redeclare */
/** @deprecated Use Card with "new" prop on it instead */
function Card(props: CardProps): React.JSX.Element;
function Card(props: NewCardProps): React.JSX.Element;

function Card(props: CardProps | NewCardProps): React.JSX.Element {
    if ('new' in props) {
        return NewCard(props);
    }
    return LegacyCard(props);
}

В итоге мы все равно экспортируем один Card:

export default Card;

Вот и все — теперь можно начинать использовать компонент. Посмотрим, как выглядит реализация Card в Storybook. Обратите внимание: один Card зачеркнут, а другой выглядит нормально. Причина в том, что у второго компонента Card есть дополнительный проп new.

Deprecation mark in IDE

А вот как это выглядит:

Components compare

Готово, на этом все.

Для AI я также создал небольшой SKILL, который может сделать это за вас. Его можно адаптировать под свои задачи. Найти его можно здесь: deprecate-react-component skill

Источник: https://dev.to/mbarzeev/deprecating-a-react-component-using-typescript-overload-2ka

Изучаем ИИ

Курс по искусственному интеллекту для веб-разработчиков.

Устанавливайте веб-приложения с новым HTML-элементом install

Для установки веб-приложений всегда требовался JavaScript. Когда вы используете событие beforeinstallprompt, весь процесс установки живет в скрипте. Новый элемент <install> меняет это: добавьте на страницу один HTML-элемент, и браузер сам отрисует надежную кнопку установки без JavaScript.

API искусственного интеллекта в браузере: как использовать Built-in AI в Chrome в реальном вебе

Браузерный ИИ уже вышел из стадии "интересной демонстрации". В Chrome появились встроенные API, которые позволяют делать перевод, определение языка, суммаризацию и генерацию текста локально на устройстве пользователя — без собственного сервера вывода модели.

Async React: создание неблокирующих UI с useTransition и useActionState

React — мощная open-source JavaScript-библиотека для построения пользовательских интерфейсов (UI), особенно для одностраничных приложений, где данные со временем меняются. Разработанная и поддерживаемая Meta (ранее Facebook), она совершила революцию в веб-разработке, представив компонентную архитектуру.

Основы квантовой информации

Узнайте о квантовых состояниях, проективных измерениях и унитарных операциях; квантовых схемах; о том, как запутанность делает возможной квантовую телепортацию, и многом другом.

Как убрать адресную строку в Trusted Web Activity

Если в Android-приложении на базе Trusted Web Activity отображается адресная строка, значит запуск произошёл не в режиме TWA, а в режиме Custom Tabs. Причина почти всегда одна: не пройдена проверка Digital Asset Links.