React
libraries
Библиотеки - это отдельные программы которые подключаются к нашей программе. В тоже время они не являются частью нашей программы. Они могут предоставлять дополнительный функционал.
libraries
Communication
DOM
Изначально HTML документ представлял статическую информацию и не предполагал динамику.
React
npx create-react-app my-app
cd my-app
npm start
Quick Start
React
Для упрощения взаимодействия с DOM деревом в react используется виртуальный DOM.
Виртуальный DOM - это легковесная копия DOM дерева но в js.
При изменении состояния react сравнивает предыдущее состояние с текущим и определяет минимальное возможное количество манипуляйций которые возможно произвести.
JSX
JSX производит «элементы» React. То, как элементы рендерятся в DOM, мы изучим в следующей главе, а ниже мы рассмотрим основы JSX, которые нужно знать начинающему.
JSX
React исходит из принципа, что логика рендеринга неразрывно связана с прочей логикой UI: с тем, как обрабатываются события, как состояние изменяется во времени и как данные готовятся к отображению.
JSX
Вместо того, чтобы искусственно разделить технологии, помещая разметку и логику в разные файлы, React разделяет ответственность с помощью слабо связанных единиц, называемых «компоненты», которые содержат и разметку, и логику.
JSX
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import reportWebVitals from './reportWebVitals';
const element = <h1>Hello, world!</h1>;
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
{ element },
</React.StrictMode>
);
JSX
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import reportWebVitals from './reportWebVitals';
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Vick',
lastName: 'Vl'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
{ element },
</React.StrictMode>
);
JSX допускает использование любых корректных JavaScript-выражений внутри фигурных скобок.
JSX
После компиляции каждое JSX-выражение становится обычным вызовом JavaScript-функции, результат которого — объект JavaScript.
Attributes in JSX
const element = <div tabIndex="0"></div>;
const element = <img src={user.avatarUrl}></img>;
Не ставьте кавычек вокруг фигурных скобок, когда используете JavaScript-выражение в значении атрибута. Следует либо применить кавычки (для строковых литералов), либо фигурные скобки (для выражений), но не то и другое вместе.
Rendering
<div id="root"></div>
Допустим, в вашем HTML-файле есть <div>:
Обычно в приложениях, написанных полностью на React, есть только один корневой элемент.
Для рендеринга React-элемента в корневой узел DOM вызовите ReactDOM.render()
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
Rendering
На практике большинство React-приложений вызывают ReactDOM.render() только один раз.
Rendering
React обновляет только то что необходимо.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
root.render(
<React.StrictMode>
{ element },
</React.StrictMode>
);
}
setInterval(tick, 1000);
Components
Функциональные компоненты
function Welcome(props) {
return <h1>Hi, {props.name}</h1>;
}
Классовые компоненты
class Welcome extends React.Component {
render() {
return <h1>Hi, {this.props.name}</h1>;
}
}
Components
Рендеринг компонентов
function Welcome(props) {
return <h1>Привет, {props.name}</h1>;
}
const element = <Welcome name="Алиса" />;
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
element,
</React.StrictMode>
);
Когда React встречает подобный элемент, он собирает все JSX-атрибуты и дочерние элементы в один объект и передаёт их нашему компоненту. Этот объект называется «пропсы» (props).
Components
Композиция компонентов
function Welcome(props) {
return <h1>Привет, {props.name}</h1>;
}
function Main() {
return (
<div>
<Welcome name="Алиса" />
<Welcome name="Базилио" />
<Welcome name="Буратино" />
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Main />,
</React.StrictMode>
);
Components
Композиция компонентов
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function UserInfo(props) {
return (
<>
<div>{props.name}</div>
<div>{props.age}</div>
</>
);
}
function Main() {
return (
<div>
<Welcome name="Alisa" />
<UserInfo name="Alisa" age="30"/>
<Welcome name="Basilio" />
<Welcome name="Booratino" />
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Main />,
</React.StrictMode>
);
Components
Обратите внимание на tag <></>
function UserInfo(props) {
return (
<>
<div>{props.name}</div>
<div>{props.age}</div>
</>
);
}
Функции которые возвращают DOM элементы должны быть обернуты в html tag, но когда бы не хотим дополнительную обертку мы используем пустой tag <></>.
Components
Components
Add classes
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
<div className="UserInfo">
Components
props
function sum(a, b) {
return a + b;
}
props можно только читать.
Компонент никогда не должен что-то записывать в свои пропсы — вне зависимости от того, функциональный он или классовый.
Такие функции называют «чистыми», потому что они не меняют свои входные данные и предсказуемо возвращают один и тот же результат для одинаковых аргументов.
Components
React-компоненты обязаны вести себя как чистые функции по отношению к своим пропсам.
Components
Компоненты можем выносить в отдельные файлы.
// ./UserInfo.jsx
function UserInfo(props) {
return (
<>
<div>{props.name}</div>
<div>{props.age}</div>
</>
);
}
Вынесем UserInfo в отдельный файл
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import reportWebVitals from './reportWebVitals';
import UserInfo from "./UserInfo";
function Welcome(props) {
return <h1>Привет, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Алиса" />
<UserInfo name="Алиса" age="30"/>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />,
</React.StrictMode>
);
reportWebVitals();
Components
Состояние приложения state
const root = ReactDOM.createRoot(document.getElementById('root'));
function Clock(props) {
return (
<div>
<h1>Привет, мир!</h1>
<h2>Сейчас {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
root.render(
<React.StrictMode>
<Clock date={new Date()} />,
</React.StrictMode>
);
}
setInterval(tick, 1000);
Рассмотрим пример с Clock.
Нужно сделать так что бы Clock обновлял себя каждую секунду.
Components
Для этого добавим так называемое «состояние» (state) в компонент Clock.
«Состояние» очень похоже на уже знакомые нам пропсы, отличие в том, что состояние контролируется и доступно только конкретному компоненту.
Components
Добавим методы жизненного цикла.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
}
componentWillUnmount() {
}
render() {
return (
<div>
<h1>Привет, мир!</h1>
<h2>Сейчас {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
Добавим методы жизненного цикла.
Метод componentDidMount() запускается после того, как компонент отрендерился.
Метод componentWillUnmount() запускается после того, как компонент удяляется.
Components
Добавим методы жизненного цикла.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Привет, мир!</h1>
<h2>Сейчас {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Clock />,
);
Добавим методы жизненного цикла.
Components
Не изменяйте состояние на прямую, только через setState.
Обновление может быть асинхронное, в таких случаях в setState передаем функцию.
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
this.setState((state, props) => {
return {
counter: state.counter + props.increment
}
});
Components
Использование хука состояния.
import React, { useState } from 'react';
function Clock(props) {
const [date, setDate] = useState('00');
return (
<div>
<h1>Привет, мир!</h1>
<h2>Сейчас {date}.</h2>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Clock date={new Date()}/>
</React.StrictMode>
);
Components
Что такое хук?
Хук — это специальная функция, которая позволяет «подцепиться» к возможностям React. Например, хук useState предоставляет функциональным компонентам доступ к состоянию React
useState — это новый способ использовать те же возможности, что даёт this.state в классах
Components
Хук эффекта даёт вам возможность выполнять побочные эффекты в функциональном компоненте:
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import reportWebVitals from './reportWebVitals';
function Clock(props) {
const [date, setDate] = useState(getTime());
useEffect(() => {
const timer = setTimeout(() => {
setDate(new Date());
}, 1000);
return () => clearTimeout(timer);
});
return (
<div>
<h1>Привет, мир!</h1>
<h2>Сейчас {date}.</h2>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Clock />
);
Components
Правила использования хуков:
- Не вызывайте хуки внутри циклов.
- Вызывайте только из React функций.
Components
Обработка событий
function sayWelcome(data) {
console.log('Welcome!', data);
}
function Main() {
return (
<div>
<Welcome name="Alisa" />
<button onClick={sayWelcome}>Say Welcome!</button>
<button onClick={sayWelcome.bind(this, 'World')}>Say Welcome2!</button>
<button onClick={() => sayWelcome("World")}>Say Welcome 3!</button>
<UserInfo name="Alisa" age="30"/>
</div>
);
}
Components
Обработка событий
function Form() {
function handleSubmit(e) {
e.preventDefault();
console.log('Отправлена форма.');
}
return (
<form onSubmit={handleSubmit}>
<button type="submit">Отправить</button>
</form>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Form />
</React.StrictMode>
);
Components
import React, { useState } from 'react'
const App = () => {
const [formValues, setFormValues] = useState([{ name: "" }])
let removeFormFields = (i) => {
let newFormValues = [...formValues];
newFormValues.splice(i, 1);
setFormValues(newFormValues)
}
let handleChange = (index, event) => {
let newFormValues = [...formValues];
newFormValues[index][event.target.name] = event.target.value;
setFormValues(newFormValues);}
let handleSubmit = (event) => { event.preventDefault(); }
return (
<form onSubmit={handleSubmit}>
{formValues.map((element, index) => (
<div className="form-inline" key={index}>
<label>Name</label>
<input type="text" name="name" value={element.name || ""} onChange={e => handleChange(index, e)} />
{
index || index === 0 ?
<button type="button" className="button remove" onClick={() => removeFormFields(index)}>Remove</button>
: null
}
</div>
))}
<div className="button-section">
<button className="button submit" type="submit">Submit</button>
</div>
</form>
)
}
Components
Form
ReactDOM.render(
<App />,
document.getElementById('root')
);
React
By Oleg Rovenskyi
React
- 276