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

14.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 Circle extends React.Component {
        render() {
            var style = {
                padding: "10px",
                margin: "20px",
                display: "inline-block",
                backgroundColor: this.props.bgColor,
                borderRadius: "50%",
                width: "100px",
                height: "100px"
            };
            return (
                <div style={style}></div>
            );
        }
    }

    ReactDOM.render(
        <div>
            <Circle bgColor="#FF0000" />
        </div>,
        document.querySelector('#container')
    );
    </script>
<body>
</html>

Этот код рисует в браузере красный круг. Теперь представим, что с сервера получены данные:

var colors = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF', '#FF00FF'];

И нам нужно создать компонент Circle для каждого элемента в этом массиве:

<!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 Circle extends React.Component {
        render() {
            var style = {
                padding: "10px",
                margin: "20px",
                display: "inline-block",
                backgroundColor: this.props.bgColor,
                borderRadius: "50%",
                width: "100px",
                height: "100px"
            };
            return (
                <div style={style}></div>
            );
        }
    }

    var colors = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#00FFFF', '#FF00FF'];
    var renderData = [];
    for (var i = 0; i < colors.length; i++) {
        renderData.push(<Circle bgColor={colors[i]} />);
    }

    ReactDOM.render(
        <div>
            {renderData}
        </div>,
        document.querySelector('#container')
    );
    </script>
<body>
</html>

Вроде все работает. Но, если открыть панель разработчика в браузере, увидим там сообщение об ошибке:

Warning: Each child in an array or iterator should have a unique "key" prop.

Мы должны для каждого компонета Circle задать свойство key с уникальным значением. Эти ключи помогают React определять, какие элементы были изменены, добавлены или удалены. Это помогает сопоставлять элементы массива с течением времени:

for (var i = 0; i < colors.length; i++) {
    var color = colors[i];
    renderData.push(<Circle key={i + color} bgColor={color} />);
}

Работа с событиями

Возьмем простой пример, состоящий из счетчика, который увеличивается каждый раз, когда присходит нажатие на кнопку.

<!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 DisplayNumber extends React.Component {
        render() {
            var style = {
                fontSize: "30px",
                fontFamily: "sans-serif",
                color: "#FFFFFF",
                fontWeight: "bold",
                marginBottom: "20px"
            };
            return (
                <div style={style}>
                    {this.props.number}
                </div>
            );
        }
    }

    class CounterWrapper extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                counter: 0
            }
        }

        render() {
            var style = {
                width: "300px",
                textAlign: "center",
                backgroundColor: "#777777",
                padding: "20px",
                fontFamily: "sans-serif",
                color: "#FFFFFF",
                borderRadius: "10px"
            }
            return (
                <div style={style}>
                    <p>Количество нажатий на кнопку</p>
                    <DisplayNumber number={this.state.counter} />
                    <button>Увеличить</button>
                </div>
            );
        }
    }

    ReactDOM.render(
        <CounterWrapper/>,
        document.querySelector('#container')
    );
    </script>
<body>
</html>

Теперь укажем событие, которое надо слушать и зададим обработчик события:

class CounterWrapper extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            counter: 0
        }
        this.increase = this.increase.bind(this);
    }

    increase(e) {
        this.setState({
            counter: this.state.counter + 1
        });
    }

    render() {
        var style = {
            width: "300px",
            textAlign: "center",
            backgroundColor: "#777777",
            padding: "20px",
            fontFamily: "sans-serif",
            color: "#FFFFFF",
            borderRadius: "10px"
        }
        return (
            <div style={style}>
                <p>Количество нажатий на кнопку</p>
                <DisplayNumber number={this.state.counter} />
                <button onClick={this.increase}>Увеличить</button>
            </div>
        );
    }
}
События передают обработчикам событий так называемые аргуметны событий. Они содержат кучу свойств, уникальные для каждого типа сбытий. Если это событие мыши, событие и его аргументы имеют тип MouseEvent. Этот объект позволяет получить доступ к данным, относящимся к мыши, о том, какая кнопка была нажата или в какой позиции экрана. Аргументы событий, связанных с нажатием клавиш на клавиатуре, имеют тип KeyboardEvent. Этот объект содержит свойства, которые позволяют определить, какая клавиша была нажата.

Синтетические события

Когда мы задаем событие с помощью JSX-кода, мы не обращаемся непосредственно к событиям DOM, вместо этого мы имеем дело с событием SyntheticEvent. Обработчики событий не получают аргументы MouseEvent или KeyboardEvent, они имеют дело с аргументами типа SyntheticEvent.

Каждое событие SyntheticEvent содержит свойства:

  • bubbles
  • cancelable
  • currentTarget
  • defaultPrevented
  • eventPhase
  • isTrusted
  • nativeEvent
  • preventDefault()
  • isDefaultPrevented()
  • stopPropagation()
  • isPropagationStopped()
  • timeStamp
  • target
  • type

Кроме того, событие SyntheticEvent, обернувшее событие MouseEvent, будет иметь доступ к характерным для мыши свойствам:

  • altKey
  • button
  • buttons
  • clientX
  • clientY
  • ctrlKey
  • getModifierState(key)
  • metaKey
  • pageX
  • pageY
  • relatedTarget
  • screenX
  • screenY
  • shiftKey

Аналогично, событие SyntheticEvent, обернувшее событие KeyboardEvent, будет иметь доступ к характерным для клавиатуры свойствам:

  • altKey
  • charCode
  • ctrlKey
  • getModifierState(key)
  • key
  • keyCode
  • locale
  • location
  • metaKey
  • repeat
  • shiftKey
  • which

Тут важно понимать, что нельзя использовать документацию по событиям DOM при работе с синтетическими событиями. Некоторые события DOM даже не существуют в React.

Работа со свойствами события

Будем увеличивать счетчик сразу на 10, если нажата клавиша Shift. Если нажата клавиша Alt — будем не увеличивать, а уменьшать счетчик.

class CounterWrapper extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            counter: 0
        }
        this.increase = this.increase.bind(this);
    }

    increase(e) {
        var current = this.state.counter;
        if (e.altKey) { // уменьшаем счетчик
            if (e.shiftKey) {
                current = current - 10;
            } else {
                current = current - 1;
            }
        } else { // увеличиваем счетчик
            if (e.shiftKey) {
                current = current + 10;
            } else {
                current = current + 1;
            }
        }
        this.setState({
            counter: current
        });
    }

    render() {
        var style = {
            width: "300px",
            textAlign: "center",
            backgroundColor: "#777777",
            padding: "20px",
            fontFamily: "sans-serif",
            color: "#FFFFFF",
            borderRadius: "10px"
        }
        return (
            <div style={style}>
                <p>Количество нажатий на кнопку</p>
                <DisplayNumber number={this.state.counter} />
                <button onClick={this.increase}>Увеличить</button>
            </div>
        );
    }
}

Поиск: JavaScript • React.js • Web-разработка • Компонент • Массив • Фреймворк • Событие • Event

Каталог оборудования
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.