Синтаксиса JSX в React упрощает работу с кодом, делая ее интуитивно-понятной, т.к. JSX, с одной стороны, очень похож на обычный HTML, с другой - позволяет внедрять переменные и свойства внутри этого синтаксиса.
Под капотом этого синтаксиса лежит метод React.createElement(), в который передается ряд параметров.
|
1 2 3 4 5 |
const element = React.createElement( 'h2', // type (HTML tag or React component) {className: 'react-test'}, // props (or attributes) 'Hello, world!' // children ); |
В качестве примера рассмотрим код для небольшого списка дел внутри React-фрагмента (<> ... <>). Здесь переменные не используются. Зато такого типа код можно добавлять там, где вы пока не создали переменные и компоненты, которые можете использовать в коде.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function TodoList() { return ( <> <h1>Hedy Lamarr's Todos</h1> <img src="https://i.imgur.com/yXOvdOSs.jpg" alt="Hedy Lamarr" className="photo" /> <ul> <li>Invent new traffic lights</li> <li>Rehearse a movie scene</li> <li>Improve spectrum technology</li> </ul> </> ); } |
Для того, чтобы вставить переменную, нужно использовать фигурные скобки. Ниже показано, что простые вычисления или использование математических или иных методов тоже требует фигурных скобок. Кроме того, на основе тернарного оператора можно указывать класс, который в React записывается, как className согласно JS, а не HTML-синтаксису.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
// Using JavaScript expressions in JSX const name = 'John'; const element = ( <div> <h1>Hello, {name}!</h1> <p>2 + 2 = {2 + 2}</p> <p>Random number: {Math.random()}</p> <div className={isActive ? 'active' : 'inactive'}> {formatDate(new Date())} </div> </div> ); |
Списки рендеринга
В React часто требуется отображать несколько похожих компонентов из коллекции данных. Такие методы массивов JavaScript, как map(), становятся чрезвычайно полезными для этой цели.
В примере ниже мы формируем список из чисел в виде маркированного списка. Обязательным в этом случае является параметр key, который может быть случайным или вполне определенным числом. Нужен он для того, чтобы проще было манипулировать элементом React при взаимодействии с ним - удалении, перемещении и т.п. Указывая key , вы помогаете React определить, какие элементы изменяются между повторными рендерами.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function NumberList() { const numbers = [100, 257, 453, 434, 567]; // трансформируем массив чисел в массив элементов React const listItems = numbers.map((number) => <li key={number}> Number: {number} </li> ); return ( <ul>{listItems}</ul> ); } |
В том случае, когда нам нужно импортировать и "разобрать" некий массив элементов на части, чтобы вывести его внутри React-приложения, код будет несколько сложнее. Например, у нас есть некий массив данных, который мы будем экспортировать из файла movies.js:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
export const ALL_MOVIES = { items: [ { id: 1, name: "The Godfather", description: "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son.", image: "https://m.media-amazon.com/images/M/MV5BM2MyNjYxNmUtYTAwNi00MTYxLWJmNWYtYzZlODY3ZTk3OTFlXkEyXkFqcGdeQXVyNzkwMjQ5NzM@._V1_FMjpg_UY1982_.jpg", rating: 4, genres: ["Crime", "Drama"], inTheaters: false, }, { id: 2, name: "The Shawshank Redemption", description: "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency.", image: "https://m.media-amazon.com/images/M/MV5BNDE3ODcxYzMtY2YzZC00NmNlLWJiNDMtZDViZWM2MzIxZDYwXkEyXkFqcGdeQXVyNjAwNDUxODI@._V1_FMjpg_UX1200_.jpg", rating: 4, genres: ["Drama"], inTheaters: false, }, { id: 3, name: "The Dark Knight", description: "When the menace known as the Joker wreaks havoc and chaos on the people of Gotham, Batman must accept one of the greatest psychological and physical tests of his ability to fight injustice.", image: "https://m.media-amazon.com/images/M/MV5BMTMxNTMwODM0NF5BMl5BanBnXkFtZTcwODAyMTk2Mw@@._V1_FMjpg_UY2048_.jpg", rating: 3, genres: ["Action", "Crime", "Drama"], inTheaters: true, }, ], }; |
Тогда в App.jsx мы запишем так:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
import {ALL_MOVIES} from './data/movies'; export default function App() { const listItems = ALL_MOVIES.items.map((movie, index) => { return <li key={index} className='movie-item'> <div className='movie-item-image-wrapper'> <img src={movie.image} alt={movie.name} /> </div> <div className="movie-item-content-wrapper"> <div className="movie-item-genres-wrapper"> { movie.genres.map(genre => <div className="movie-item-genre-tag">{genre}</div>) } </div> <div className="movie-item-description-wrapper"> <h3 className='movie-item-title'>{movie.name}</h3> <p className='movie-item-description'>{movie.description}</p> </div> <div className="movie-item-rating-wrapper"> <span className="movie-item-rating-text"> Rating: {movie.rating || 0}/5 </span> <div className="movie-item-star-icon-wrapper"> {[1, 2, 3, 4, 5].map((star) => ( <span aria-label={`Rate ${movie.name} with ${star} star${ star > 1 ? "s" : "" }`} key={star} className={`movie-item-star-icon-button ${ star <= (movie.rating || 0) ? "text-yellow-500" : "text-gray-400 hover:text-yellow-300" }`} > ★ </span> ))} </div> </div> </div> </li> }); return ( <div className="app"> <ul className='movie-list'>{listItems}</ul> </div> ); } |
Обратите внимание, что в js-файле у нас есть объект, в котором свойство items уже содержит сам массив данных. Поэтому и метод map() мы будем вызывать для ALL_MOVIES.items.
Условный рендеринг
Условный рендеринг позволяет отображать различные элементы пользовательского интерфейса в зависимости от определённых условий. Вы можете использовать условные конструкции JavaScript в виде операторов if...else, тернарных операторов, а также логическое И ( &&) для создания элементов, представляющих текущее состояние.
Пример с выводом сообщения о температуре:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// Conditional rendering examples function WeatherInfo({ temperature }) { // Метод 1: Конструкция if ... else вне JSX let weatherMessage; if (temperature > 30) { weatherMessage = <p>Снаружи жарко!</p>; } else { weatherMessage = <p>Сейчас холодно, надень жакет.</p>; } return ( <div> {weatherMessage} {/* Метод 2: Тернарный оператор */} <p>{temperature > 25 ? 'Слишком жарко' : 'Отлично'}</p> {/* Метод 3: Логическое И */} {temperature > 32 && <p>Предупреждение: Ну, очень жарко!</p>} </div> ); } |
Довольно часто в React какие-то условия предполагают, что какой-то элемент существует. В этом случае нужно записывать выражение с использованием логического оператора &&:{condition && <div>Content</div>}
Например, в коде для фильмов можно добавить
|
1 2 3 4 5 6 7 |
{movie?.inTheaters && ( <div className="movie-item-theaters-banner"> <span className="movie-item-theaters-banner-text"> Now Playing </span> </div> )} |
Кроме того, если, например, некое свойство может отсутствовать в массиве объектов, например тот же рейтинг или изображение, проверять его можно так: const notRated = !movie?.rating; Тут используется оператор опциональной последовательности, который возвращает undefined, если какое-либо свойство отсутствует у нужного объекта.
Например, так можно в коде фильмов проверять наличие изображения и выводить в зависимости от этого либо нужное изображение, либо сообщение об его отсутствии.
|
1 2 3 4 5 6 7 8 9 10 11 |
{movie?.image ? ( <img src={movie.image} className="movie-item-image" alt={movie.name} /> ) : ( <div className="movie-item-no-image"> <span className="movie-item-no-image-text">No image</span> </div> )} |