React.js. Начало работы. Часть 2 из 12

13.10.2019

Теги: JavaScriptReact.jsWeb-разработкаКомпонентФреймворк

Композиция компонентов

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

Пример композиции из нескольких компонентов:

<!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>
Разработанный комитетом ES6/ES2015 оператор расширения предназначен для работы с массивами. Тот факт, что он работает с объектным литералом, таким как объект 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:

  1. Метод componentDidMount() вызывается сразу после того, как компонент визуализируется (рендерится)
  2. Метод 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

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.