React.js. Начало работы. Часть 2 из 12
13.10.2019
Теги: JavaScript • React.js • Web-разработка • Компонент • Фреймворк
Композиция компонентов
Компоненты могут состоять из других компонентов. Простой пример — какой-нибудь список элементов, например меню сайта. Каждый элемент меню может быть представлен отдельным компонентом, а само меню также может представлять собой компонент.
Пример композиции из нескольких компонентов:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>React</title> <script src="https://unpkg.com/react@16.0.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.0.0/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> class Square extends React.Component { render() { var squareStyle = { height: "150px", backgroundColor: this.props.color }; return ( <div style={squareStyle}></div> ); } } class Label extends React.Component { render() { var labelStyle = { fontFamily: "sans-serif", fontWeight: "bold", textAlign: "center" }; return ( <p style={labelStyle}>{this.props.color}</p> ); } } class Card extends React.Component { render() { var cardStyle = { height: "200px", width: "150px", padding: 0, margin: "10px", backgroundColor: "#FFFFFF", boxShadow: "0 0 7px #777777", display: "inline-block" }; return ( <div style={cardStyle}> <Square color={this.props.color}/> <Label color={this.props.color}/> </div> ); } } ReactDOM.render( <div> <Card color="#FF0000"/> <Card color="#00AA00"/> <Card color="#0000FF"/> </div>, document.querySelector('#container') ); </script> <body> </html>
Здесь мы вызываем компоненты Square
и Label
изнутри компонента Card
.
Передача свойств
В React свойства должны передаваться от родительского компонента к непосредственному дочернему компоненту. При передаче свойства нельзя пропустить дочерний уровень. И потомки не могут отправить свойство обратно предку. Все связи однонаправлены — от предка к потомку.
Если между предком и потомком есть несколько промежуточных компонентов, свойства надо передвать по всей цепочке последовательно.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>React</title> <script src="https://unpkg.com/react@16.0.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.0.0/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> class Display extends React.Component { render() { return ( <div> <p>{this.props.color}</p> <p>{this.props.number}</p> <p>{this.props.size}</p> </div> ); } } class Label extends React.Component { render() { return ( <Display color={this.props.color} number={this.props.number} size={this.props.size} /> ); } } class Shirt extends React.Component { render() { return ( <div> <Label color={this.props.color} number={this.props.number} size={this.props.size} /> </div> ); } } ReactDOM.render( <div> <Shirt color="white" number="14" size="medium" /> </div>, document.querySelector('#container') ); </script> <body> </html>
Этот пример можно упростить, если использовать оператор расширения {...this.props}
:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>React</title> <script src="https://unpkg.com/react@16.0.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.0.0/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> class Display extends React.Component { render() { return ( <div> <p>{this.props.color}</p> <p>{this.props.number}</p> <p>{this.props.size}</p> </div> ); } } class Label extends React.Component { render() { return ( <Display {...this.props} /> ); } } class Shirt extends React.Component { render() { return ( <div> <Label {...this.props} /> </div> ); } } ReactDOM.render( <div> <Shirt color="white" number="14" size="medium" /> </div>, document.querySelector('#container') ); </script> <body> </html>
props
, является результатом того, что это расширение стандарта React.
Работа с состоянием
Компоненты, которые мы создавали до этого момента, были stateless
, то есть не содержали никакого состояния и могли только отрисовывать переданные свойства. Теперь создадим простой пример счетчика времени, который умеет сохранять свое состояние:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>React</title> <script src="https://unpkg.com/react@16.0.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.0.0/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> </head> <body> <div id="container"></div> <script type="text/babel"> class TimeCounter extends React.Component { render() { return ( <div> <p>Количество секунд с момента запуска:</p> <h1>Счетчик</h1> </div> ); } } class DisplayCounter extends React.Component { render() { var style = { width: "300px", textAlign: "center", backgroundColor: "#777777", padding: "20px", fontFamily: "sans-serif", color: "#FFFFFF", borderRadius: "10px" } return ( <div style={style}> <TimeCounter/> </div> ); } } ReactDOM.render( <DisplayCounter/>, document.querySelector('#container') ); </script> <body> </html>
Чтобы все заработало, будем использовать API-интерфейсы, которые предоставляет компонент React:
- Метод
componentDidMount()
вызывается сразу после того, как компонент визуализируется (рендерится) - Метод
setState()
позволяет обновить состояние, т.е. обновить значение свойстваstate
объекта
Нам понадобится переменная counter
, которая будет выполнять роль счетчика. Эта переменная является частью состояния компонента. Нам нужно создать объект state
, сделать переменную counter
его свойством и убедиться, что мы все это сделали до того, как компонент будет создан:
class TimeCounter extends React.Component { constructor(props) { super(props); this.state = { counter: 0 }; } render() { return ( <div> <p>Количество секунд с момента запуска:</p> <h1>{this.state.counter}</h1> </div> ); } }
Будем использовать функцию setInterval()
, чтобы увеличивать значение свойства counter
на единицу каждую секунду:
class TimeCounter extends React.Component { constructor(props) { super(props); this.state = { counter: 0 }; this.timer = this.timer.bind(this); } componentDidMount() { setInterval(this.timer, 1000) } timer() { this.setState({ counter: this.state.counter + 1 }); } render() { return ( <div> <p>Количество секунд с момента запуска:</p> <h1>{this.state.counter}</h1> </div> ); } }
Поиск: JavaScript • Web-разработка • Компонент • Фреймворк • React.js • Состояние • state