Поиск по сайту:

Условный рендеринг в React


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

Понимание проблемы

Традиционные системы шаблонов упрощают реализацию условного рендеринга. Вот как это можно сделать в Handlebars, механизме шаблонов JavaScript:

<div class="profile">
{{#if user}}
<p>You are logged in!</p>
{{else}}
<a href="/login">Login</a>
</div>
{{/if}}

При работе в React вы обычно будете писать JSX. Хотя JSX выглядит как HTML, процесс сборки React преобразует его в обычный JavaScript. Это заканчивается серией вызовов React.createElement().

Это означает, что вы не можете использовать неизмененные условные выражения JavaScript внутри JSX. Попытка сделать что-то подобное вызовет ошибку компиляции:

const MyComponent = props => {
    return (
        <div>
            if (props.user) {
                <p>You are logged in!</p>
            }
            else <a href="/login">Login</a>
        </div>
    );
};

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

Выход из JSX

Самый простой способ исправить приведенный выше код — удалить if из оператора return:

const MyComponent = props => {
    if (props.user) {
        return <p>You are logged in!</p>;
    }
    else {
        return <a href="/login">Login</a>;
    }
};

Условие было удалено из JSX. Вместо этого используются два независимых узла JSX, причем возвращаемый узел определяется оператором if в теле функции. Такой подход вполне понятен и полностью разделяет две ветви.

Использование условных выражений

Приведенное выше решение обычно работает только в самых простых компонентах. Вы, как правило, в конечном итоге дублируете код, например <div> верхнего уровня, присутствующий в обоих узлах JSX в примере.

В большинстве случаев вам понадобится что-то более элегантное. JSX поддерживает выражения JavaScript, заключенные в фигурные скобки ({}). Вы можете использовать логические сравнения и тернарный оператор для встроенного условного рендеринга.

const MyComponent = props => {
    return (
        <div>
            {props.user ? <p>You are logged in!</p> : <a href="/login">Login</a>}
        </div>
    );
};

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

Встроенные выражения — это наиболее часто используемый метод условного рендеринга JSX. Однако они могут требовать когнитивных усилий, особенно если возвращаемые значения true и false сами по себе являются выражениями. Когда выражение становится громоздким, его можно разбить на несколько строк. Это может улучшить читаемость и помочь сохранить файл в пределах длины строки, установленных вашим линтером.

Сценарии, в которых нет «иначе»

Давайте теперь адаптируем приведенный выше пример, удалив текст «вы вошли в систему». Наш менеджер по продукту решил, что в этом разделе приложения нет необходимости. Контейнер <div> теперь должен быть пустым, когда пользователь входит в систему.

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

const MyComponent = props => {
    return (
        <div>
            {props.user ? null : <a href="/login">Login</a>}
        </div>
    );
};

React также поддерживает false с тем же значением, что и null. Это означает, что вы можете сократить приведенное выше, используя оператор JavaScript && (и) для логического сравнения.

const MyComponent = props => {
    return (
        <div>
            {!props.user && <a href="/login">Login</a>}
        </div>
    );
};

Левая часть выражения будет оценена как false, когда пользователь войдет в систему. Поскольку две стороны соединены с помощью и, общее выражение также оценивается как <ложь. Следовательно, ничего не отображается, когда пользователь входит в систему.

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

Оценки JavaScript «замкнуты». Это означает, что JSX в правой части не будет создаваться без необходимости, если левое выражение оценивается как false.

Значения условной опоры

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

const MyComponent = props => {
    return (
        <div>
            <a href={(props.user.loggedIn === true) ? "/dashboard" : "/home"}>
                Home
            </a>
        </div>
    );
};

В этом примере место назначения ссылки «Домой» динамически корректируется в зависимости от того, вошел ли пользователь в систему. Помните, что props компонента в JSX транспилируются в простой объект JavaScript, поэтому этот метод работает. Вы действительно пишете следующее:

React.createElement("a", {
    href: (props.user.loggedIn === true) ? "/dashboard" : "/home"
});

JSX — это просто расширение синтаксиса JavaScript, которое позволяет вам объявлять компоненты React в форме, напоминающей HTML.

Условные выражения с использованием логических компонентов

Еще один способ добиться условного рендеринга — включить в проект так называемые «логические» компоненты. Это простые компоненты, которые отображают своих дочерних элементов только в том случае, если выполняется условие.

const IfComponent = props => {
    if (props.condition) return props.children;
    else return null;
}
 
const MyComponent = props => (
    <IfComponent condition={props.user.isLoggedIn}>
        <a href="/logout">Logout</a>
    </IfComponent>
);

Этот шаблон может сделать код в вашей функции render() более интуитивно понятным. Однако есть одна большая проблема — элемент a будет отображаться всегда, даже если условие if не выполняется. Вы можете решить эту проблему, адаптировав IfComponent так, чтобы он вызывал функцию вместо непосредственного рендеринга потомков.

const IfComponent = props => {
    if (props.condition) return props.renderChildren();
    else return null;
}
 
const renderContent = () => <a href="/logout">Logout</a>;
 
const MyComponent = props => (
    <IfComponent
        condition={props.user.isLoggedIn}
        renderContent={renderContent} />
);

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

Вариантом этого шаблона является создание компонента более высокого порядка (HOC). Это позволяет обернуть компонент условной функциональностью.

const ifHoc = (condition, component) => {
    return props => {
        if (condition()) return component(props);
        else return null;
    };
}
 
const LogoutLink = () => <a href="/logout">Logout</a>;
 
const LogoutLinkOnlyWhenLoggedIn = ifHoc(props => props.loggedIn, LoginLink);
-
const ComponentUsingLoginLink = props => (
    <LogoutLinkOnlyWhenLoggedIn loggedIn={props.user.isLoggedIn} />
);

Сначала этот подход может быть немного сложнее понять. Лучше всего, если вы хотите, чтобы компонент отображался полностью отдельно от условной логики. Это также позволяет повторно использовать сложную логику, так как любой компонент можно обернуть с помощью ifHoc(). HOC упаковывает исходный компонент и отображает его только тогда, когда переданный условный функционал возвращает true.

Проблемы с производительностью

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

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

Заключение

React требует, чтобы вы подходили к условному рендерингу немного иначе, чем к традиционным системам шаблонов. Это связано с тем, что JSX только выглядит как HTML. Он передается обратно в объекты JavaScript, которые затем используются с вызовами функций React.

Тем не менее, у вас есть множество доступных вариантов, когда вам нужно условно визуализировать компонент. Самый простой вариант — написать условные выражения внутри вашего JSX, используя либо &&, либо тернарный синтаксис. Вы можете вернуться к реальному if в корне вашего метода render() или принять компонент более высокого порядка, если выражения JSX сделают ваш процесс рендеринга более сложным для понимания.




Все права защищены. © Linux-Console.net • 2019-2024