2.8 Отрисовка по условию
В React вы можете создавать определенные компоненты, которые инкапсулируют необходимое поведение. Далее, в зависимости от состояния вашего приложения, можно отрисовывать только некоторые из них.
В React отрисовка по условию работает также, как и условия в JavaScript. Используйте условные операторы JavaScript,
такие как if
или тернарный оператор
, чтобы создавать элементы, представляющие текущее
состояние. Затем позвольте React обновить UI, чтобы привести элементы и состояние в соответствие.
Рассмотрим два компонента:
function ErrorMessage(props) {
return <h3>Произошла ошибка на сервере. Не удалось сохранить ваши данные.</h3>;
}
function SuccessMessage(props) {
return <h3>Ваши данные успешно сохранены!</h3>;
}
Давайте создадим компонент Response
, который отображает один из этих компонентов,
в зависимости от результата сохранения данных на сервере:
function Response(props) {
const isSuccess = props.isSuccess;
if (isSuccess) {
return <SuccessMessage/>;
}
return <ErrorMessage/>;
//или
//return isSuccess ? <SuccessMessage/> : <ErrorMessage/>
}
// Можете поменять на isSuccess={false}:
ReactDOM.render(<Response isSuccess={true} />, document.getElementById('root'));
Этот пример отрисовывает различные сообщения в зависимости от значения свойства isSuccess
.
Вы можете использовать переменные, чтобы хранить элементы. Это позволяет отрисовывать по условию только часть компонента, в то время как оставшаяся часть не изменится.
Пусть у нас есть камин с двумя кнопками управления. Кнопки представим в виде
компонентов SetFire
и SnuffOut
:
function SetFireButton(props) {
return (<button className="orange" onClick={props.onClick}>Зажечь</button>);
}
function SnuffOutButton(props) {
return (<button className="blue" onClick={props.onClick}>Потушить</button>);
}
Далее создадим компонент с состоянием под названием FirePlace
.
Он будет отрисовывать либо <SetFireButton />
, либо <SnuffOutButton />
в
зависимости от его текущего состояния. Также он будет отрисовывать компонент <Indicator />
,
показывающий сообщения о состоянии нашего камина:
class FirePlace extends React.Component {
constructor(props) {
super(props);
this.onSetFire = this.onSetFire.bind(this);
this.onSnuffOut = this.onSnuffOut.bind(this);
this.state = {isBurning: false};
}
onSetFire() {
this.setState({isBurning: true});
}
onSnuffOut() {
this.setState({isBurning: false});
}
render() {
const isBurning = this.state.isBurning;
let button = null;
if(isBurning){
button = <SnuffOutButton onClick={this.onSnuffOut} />
} else {
button = <SetFireButton onClick={this.onSetFire} />;
}
return (
<div>
<Indicator isBurning={isBurning} />
{button}
</div>
);
}
}
Использование переменной и оператора if
– хороший способ
отрисовывать компонент по условию. Но что если иногда хочется использовать более короткий синтаксис?
Есть несколько способов встроить условия в JSX, рассмотрим их ниже.
Вы можете встраивать любые выражения в JSX, оборачивая их в фигурные скобки. Сюда
относится и логический оператор &&
JavaScript. Это удобно для добавления
элемента по условию:
function Console(props) {
const errors = props.errors;
return (
<p>
<h3>Attention!</h3>
{errors.length > 0 &&
<p>You have <b>{errors.length}</b> errors.</p>
}
</p>
);
}
const errors = [
'Failed to load resource: net::ERR_INSECURE_RESPONSE',
'TypeError: e is undefined',
'Uncaught ReferenceError: calculate is not defined'
];
ReactDOM.render(<Console errors={errors} />, document.getElementById('root'));
Этот код работает, потому что в JavaScript true && выражение
всегда
возвращает выражение
, а false && выражение
всегда
возвращает false
.
Следовательно, если условие истинно, элемент появится в результате вывода прямо
после &&
. Если условие ложно, React пропустит его.
Другой метод отрисовать элемент по условию в JSX-выражении - использовать
тернарный оператор JavaScript: условие ? true : false
В примере ниже мы используем его для отрисовки по условию маленького блока текста:
render() {
const isSent = this.state.isSent;
return (
<p>
<h3>Ваше сообщение {isSent ? 'успешно' : 'не'} отправлено</h3>
</p>
);
}
Оператор может оказаться полезным и для более длинных выражений, даже если код может показаться менее читабельным:
render() {
const isNew = this.state.isNew;
return (
<div>
{isNew ? (
<div>
<EditButton onClick={this.onEdit} />
<DeleteButton onClick={this.onDelete} />
</div>
) : (
<AddButton onClick={this.onAdd} />
)
}
</div>
);
}
Как и в JavaScript, именно вам предстоит выбрать подходящий стиль кода, который будет максимально читабелен для всей вашей команды. Также помните, что как только условия становятся слишком сложными, возможно, наступило отличное время выделить компонент.
В редких случаях вам нужно, чтобы компонент себя скрыл, даже если он был отрисован
другим компонентом. Чтобы это сделать, нужно вернуть null
, вместо результата его отрисовки.
В примере ниже <DangerAlert />
отрисовывается в зависимости от значения
переменной состояния isDangerAlertShowed
. Если её значение равно false
, то
компонент не отрисовывается:
function DangerAlert(props) {
return (
<h3 className="alert alert-danger">{props.text}</h3>
);
}
class Application extends React.Component {
constructor(props) {
super(props);
this.state = {isDangerAlertShowed: true}
this.toggleDangerAlert = this.toggleDangerAlert.bind(this);
}
toggleDangerAlert() {
this.setState(prevState => ({
isDangerAlertShowed: !prevState.isDangerAlertShowed
}));
}
render() {
return (
<div>
{this.state.isDangerAlertShowed ?
<DangerAlert text={'Внимание! В приложении возникли некоторые проблемы!'} /> : null}
<button onClick={this.toggleDangerAlert}>
{this.state.isDangerAlertShowed ? 'Скрыть' : 'Показать'}
</button>
</div>
);
}
}
ReactDOM.render(<Application />, document.getElementById('root'));
Когда мы возвращаем null
из метода render
, это никак не влияет на срабатывание
методов жизненного цикла. К примеру, по-прежнему будут вызываться componentWillUpdate
и componentDidUpdate
.