Финал 7 принципов надежного проектирования компонентов React

JavaScript React.js
Финал 7 принципов надежного проектирования компонентов React

Перевод: Лю Сяоси

Оригинальная ссылка:Рисовое путешествие avlutin.com/7-architect…

В этой статье основное внимание уделяется тому, чтобы быть проверяемым и осмысленным. Из-за ограниченного уровня некоторые переводы в тексте могут быть недостаточно точными, если у вас есть идеи получше, укажите их в комментариях.

несмотря на то что组合,复用а также纯组件Три принципа, похоже, не очень популярны на платформе Nuggets, но, исходя из принципа наличия начала и конца, конечно, лично я все еще считаю, что эта статья очень качественная, и я все же настаиваю на завершении. перевод. Эта статья последняя可靠React组件设计Последняя статья, я надеюсь, будет полезна для вашего дизайна компонентов.

Другие статьи можно нажать:GitHub.com/Иветт Л.А. Ю/Б…

——————————————— Я — разделительная линия ————————————————

Если вы не читали первые несколько принципов:

Тестируемый и проверенный

после тестированияКомпонент проверяет, что его выходные данные соответствуют ожиданиям с учетом входных данных.

ТестируемыйКомпоненты легко проверить.

Как я могу убедиться, что компоненты работают должным образом? Можно с неодобрением сказать: «Проверил вручную».

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

Вот почему так важно автоматизировать проверку компонентов: проводить модульные тесты. Модульное тестирование гарантирует, что каждый раз, когда вносятся изменения, компонент работает правильно.

Модульное тестирование — это не только раннее обнаружение ошибок. Еще одним важным аспектом является возможность проверки правильности архитектуры компонентов.

Мне показалось особенно важным следующее:

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

Компонент часто трудно тестировать, потому что он имеет многоprops, зависимости, необходимость в прототипах и доступ к глобальным переменным — все это признаки плохого дизайна.

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

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

Практический пример: возможность тестирования означает хороший дизайн

Давайте проверим этоГлава пакетадве версии<Controls>компоненты.

import assert from 'assert';
import { shallow } from 'enzyme';

class Controls extends Component {
    render() {
        return (
            <div className="controls">
                <button onClick={() => this.updateNumber(+1)}>
                    Increase
                </button>
                <button onClick={() => this.updateNumber(-1)}>
                    Decrease
                </button>
            </div>
        );
    }
    updateNumber(toAdd) {
        this.props.parent.setState(prevState => ({
            number: prevState.number + toAdd
        }));
    }
}

class Temp extends Component {
    constructor(props) {
        super(props);
        this.state = { number: 0 };
    }
    render() {
        return null;
    }
}

describe('<Controls />', function () {
    it('should update parent state', function () {
        const parent = shallow(<Temp />);
        const wrapper = shallow(<Controls parent={parent} />);

        assert(parent.state('number') === 0);

        wrapper.find('button').at(0).simulate('click');
        assert(parent.state('number') === 1);

        wrapper.find('button').at(1).simulate('click');
        assert(parent.state('number') === 0);
    });
});

Мы видим, что<Controls>Его сложно протестировать, потому что он зависит от деталей реализации родительского компонента.

При тестировании требуется дополнительный компонент<Temp>, который имитирует родительский компонент, проверяет<Controls>Правильно ли изменено состояние родительского компонента.

когда<Controls>Тестирование становится проще, когда оно не зависит от деталей реализации родительского компонента. Теперь посмотрим, как тестируется правильно упакованная версия:

import assert from 'assert';
import { shallow } from 'enzyme';
import { spy } from 'sinon';

function Controls({ onIncrease, onDecrease }) {
    return (
        <div className="controls">
            <button onClick={onIncrease}>Increase</button>
            <button onClick={onDecrease}>Decrease</button>
        </div>
    );
}

describe('<Controls />', function () {
    it('should execute callback on buttons click', function () {
        const increase = sinon.spy();
        const descrease = sinon.spy();
        const wrapper = shallow(
            <Controls onIncrease={increase} onDecrease={descrease} />
        );

        wrapper.find('button').at(0).simulate('click');
        assert(increase.calledOnce);
        wrapper.find('button').at(1).simulate('click');
        assert(descrease.calledOnce);
    });
});

Хорошо упакованные компоненты легко тестировать, и наоборот, компоненты, которые не упакованы должным образом, трудно тестировать.

Тестируемость — это практический критерий для определения того, насколько хорошо сконструирован компонент.

осмысленный

Легко увидеть, что делает значимый компонент.

Читабельность кода очень важна, сколько раз вы использовали запутанный код? Вы видите строку, но не знаете, что она означает.

Разработчики тратят большую часть своего времени на чтение и понимание кода, а не на его написание. Мы тратим 75% нашего времени на понимание кода, 20% нашего времени на изменение существующего кода и только 5% на написание нового кода.

Дополнительное время, потраченное на удобочитаемость, сокращает время понимания для будущих товарищей по команде и для вас самих. Практика именования становится важной по мере роста приложения, потому что понимание работы увеличивается с объемом кода.

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

именование компонентов

Номенклатура Паскаля

Имена компонентов объединяются одним или несколькими словами Паскаля (в основном существительными), такими как:<DatePicker>,<GridItem>,Application,<Header>.

специализация

Чем более специализирован компонент, тем больше слов может содержать его имя.

по имени<HeaderMenu>Компонент указывает, что в заголовке есть меню. имя<SidebarMenuItem>Представляет пункт меню, расположенный на боковой панели.

Компоненты легко понять, когда их названия темные. Для этого обычно приходится использовать подробные имена. Это нормально: больше деталей лучше, чем меньше ясности.

Допустим, вы перемещаетесь по некоторым файлам проекта и определяете 2 компонента:<Authors>а также<AuthorsList>. Основываясь только на названии, можете ли вы провести различие между ними? Скорее всего нет.

Для получения подробной информации необходимо открыть<Authors>исходные файлы и просмотреть код. слово после того, как вы знаете<Authors>Получить список авторов с сервера и отрендерить<AuthorsList>компоненты.

более профессиональное имя вместо<Authors>Эта ситуация не будет создана. Лучше такие имена, как:<FetchAuthors>,<AuthorsContainer>или<AuthorsPage>.

слово - понятие

Слово представляет понятие. Например, коллекция, представляющая концепцию элемента, представлена ​​словом списка.

Каждое понятие соответствует слову, и связь затем сохраняется согласованной во всем приложении. В результате получается предсказуемое сопоставление слов и понятий.

Удобочитаемость страдает, когда много слов представляют одну и ту же концепцию. Например, вы определяете компонент списка порядка рендеринга как:<OrdersList>, определите другой компонент, который отображает список расходов как:<ExpensesTable>.

Одна и та же концепция коллекции элементов рендеринга представлена ​​двумя разными словами:listа такжеtable. Нет причин использовать разные слова для одного и того же понятия. Это добавляет путаницы и нарушает согласованность имен.

Назовите компонент как<OrdersList>а также<ExpensesList>(использоватьlist)или<OrdersTable>а также<ExpensesTable>(использоватьtable). Используйте любое слово, которое вам кажется более подходящим, просто будьте последовательны.

Примечания

Значимых имен для компонентов, методов и переменных достаточно, чтобы сделать код читабельным. Поэтому комментарии в основном излишни.

Практический пример: Написание самообъясняющего кода

Распространенным неправильным использованием аннотаций является интерпретация нераспознанных и неоднозначных имен. Давайте рассмотрим такой пример:

// <Games> 渲染 games 列表
// "data" prop contains a list of game data
function Games({ data }) {
    // display up to 10 first games
    const data1 = data.slice(0, 10);
    // Map data1 to <Game> component
    // "list" has an array of <Game> components
    const list = data1.map(function (v) {
        // "v" has game data
        return <Game key={v.id} name={v.name} />;
    });
    return <ul>{list}</ul>;
}

<Games
    data=[{ id: 1, name: 'Mario' }, { id: 2, name: 'Doom' }]
/>

Комментарии в приведенном выше примере поясняют непонятный код.<Games>,data, data1, v,количество10бессмысленны и непонятны.

При рефакторинге компонентов используйте осмысленныеpropsимя и имя переменной, то комментарий можно опустить:

const GAMES_LIMIT = 10;

function GamesList({ items }) {
    const itemsSlice = items.slice(0, GAMES_LIMIT);
    const games = itemsSlice.map(function (gameItem) {
        return <Game key={gameItem.id} name={gameItem.name} />;
    });
    return <ul>{games}</ul>;
}

<GamesList
    items=[{ id: 1, name: 'Mario' }, { id: 2, name: 'Doom' }]
/>

Не используйте комментарии для объяснения кода, код — это комментарии. (Примечание Сяо Си: многие люди могут не иметь возможности комментировать код. Кроме того, из-за непостоянного уровня членов команды все должны писать соответствующие комментарии)

Выразительная лестница

Выразительность компонента я разделил на 4 шага. Чем ниже находится компонент по лестнице, тем больше усилий требуется для его понимания.

Вы можете понять, что делает компонент, несколькими способами:

  • читать имена переменных иprops
  • Читать документацию/примечания
  • просмотреть код
  • Проконсультируйтесь с автором

Если имя переменной иpropsПредоставляет достаточно информации, чтобы вы поняли, что делает этот компонент и как его использовать, это супер выразительная сила. Старайтесь поддерживать этот высокий уровень качества.

Некоторые компоненты имеют сложную логику, и даже хорошее название не обеспечивает необходимой детализации. Тогда вам нужно читать документацию.

Если документация отсутствует или не на все вопросы есть ответы в документации, вам придется пройтись по коду. Это не лучший вариант из-за дополнительных затрат времени, но приемлемый.

Если просмотр кода также не помогает понять компонент, следующим шагом будет запрос подробностей у автора компонента. Это определенно неправильное название, и его следует избегать на этом этапе. Лучше, чтобы автор провел рефакторинг кода или рефакторил код самостоятельно.

продолжай улучшать

Переписывание — это суть письма. Профессиональные писатели переписывают свои предложения снова и снова.

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

Интересно, что та же концепция перезаписи применима и к компонентам дизайна. Иногда создать правильную структуру компонентов с первого раза практически невозможно, потому что:

  • Плотный график проекта не позволяет уделять достаточно времени проектированию системы.
  • Изначально выбранный метод был неправильным
  • Только что нашел библиотеку с открытым исходным кодом, которая лучше справляется с решением проблемы.
  • или любая другая причина.

Чем сложнее компонент, тем больше требуется проверки и рефакторинга.

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

На самом деле разработка — это бесконечный процесс, в ходе которого можно пересматривать предыдущие решения и вносить улучшения.

надежность имеет значение

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

Поэтому разработка относительно удобна на любом этапе проекта.

С другой стороны, по мере увеличения размера системы вы можете забыть о планировании и периодической корректировке структуры для уменьшения связанности. Просто для реализации функции.

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

Чем закончилась грустная история? Вы можете отказаться от текущей системы и переписать код с нуля, а можете просто продолжать есть кактусы. Я съел много кактусов, и ты, наверное, тоже, и это было не самое лучшее чувство.

Решение простое, но требовательное: напишите надежные компоненты.

В заключение

Семь упомянутых выше принципов иллюстрируют одну и ту же идею с разных точек зрения:

Надежный компонент реализует ответственность, скрывает свою внутреннюю структуру и обеспечивает эффективноеpropsконтролировать его поведение.

Единая ответственность и инкапсуляцияsolidОснова дизайна. (Возможно, вам нужно понять, что такое твердый принцип.)

Single Responsibility рекомендует создавать компонент, который реализует только одну ответственность и имеет причину для изменения.

Хорошо инкапсулированные компоненты скрывают свою внутреннюю структуру и детали реализации и определяютpropsуправлять поведением и выводом.

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

Многоразовые компоненты являются результатом хорошо спроектированной системы. Используйте код как можно чаще, чтобы избежать дублирования.

Побочные эффекты, такие как сетевые запросы или глобальные переменные, делают компоненты зависимыми от среды. тем жеpropЗначения возвращают один и тот же вывод, чтобы сделать их чистыми.

Значимые имена компонентов и выразительный код — ключи к удобочитаемости. Ваш код должен быть простым для понимания и чтения.

Тестирование — это не просто способ автоматического обнаружения ошибок. Если вы обнаружите, что компонент сложно тестировать, возможно, он неправильно спроектирован.

Успешные приложения зависят от надежных компонентов, поэтому важно создавать надежные, масштабируемые и удобные в сопровождении компоненты.

Какие принципы вы считаете полезными при написании компонентов React?

Наконец, спасибо за вашу готовность потратить свое драгоценное время на чтение этой статьи. Если эта статья дала вам небольшую помощь или вдохновение, пожалуйста, не скупитесь на лайки и звезды. двигаться вперед.GitHub.com/Иветт Л.А. Ю/Б…

Подпишитесь на официальный аккаунт и присоединитесь к группе технического обмена