React.js. Начало работы. Часть 3 из 12
14.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 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