JavaScript Crash Course
React
12
Зміст:
-
Hooks
-
State
-
Lifecycle
-
Рендеринг з умовами
-
Опрацювання подій
-
Робота з формами
-
Робота з HTTP запитами
State
React State
State може містити будь-яке значення JavaScript, включаючи об’єкти. Так, як state - це read-only об'єкт ми не повинні безпосередньо змінювати значення, які збегіраються в стані React.
Саме тому потрібно використовувати React.useState() hook.
const [x, setX] = useState(0);
React State та початковий стан
import { useState } from 'react';
function MyComponent() {
const [age, setAge] = useState(28);
const [name, setName] = useState('Taylor');
const [todos, setTodos] = useState(() => createTodos());
// ...
import { useState } from 'react';
export default function MovingDot() {
const [position, setPosition] = useState({ x: 0, y: 0 });
return (
<div
onPointerMove={e => {
position.x = e.clientX;
position.y = e.clientY;
}}
style={{
position: 'relative',
width: '100vw',
height: '100vh',
}}>
<div style={{
position: 'absolute',
backgroundColor: 'red',
borderRadius: '50%',
transform: `translate(${position.x}px, ${position.y}px)`,
left: -10,
top: -10,
width: 20,
height: 20,
}} />
</div>
);
}
Життєвий цикл компонентів
Lifecycle
Життєвий цикл компонента є однією з найважливіших концепцій React.
Методи життєвого циклу дають нам багато можливостей контролювати оновлення програм тощо.
Mounting
Updating
Unmounting
Методи класового компоненту
React API надає кілька методів життєвого циклу для компонентів класу. Найважливішими з них є componentDidMount, componentDidUpdate, componentWillUnmount.
Монтування та componentDidMount
Послідовність відпрацювання:
- constructor()
- static getDerivedStateFromProps()
- render()
- componentDidMount()
Оновлення з використанням componentDidUpdate
Оновлення викликано props або змінами стану. Це відбувається в такому порядку:
- static getDerivedStateFromProps()
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
Демонтування компонента
componentWillUnmount() викликається безпосередньо перед демонтуванням компонента. Цей метод використовують, щоб очистити необхідні таймери та підписки або скасувати мережеві запити.
Інші методи життєвого циклу класових компонентів
getDerivedStateFromProps(props, state)
componentDidCatch(error, info)
forceUpdate(callback)
componentWillReceiveProps(nextProps)
componentWillReceiveProps(nextProps)
getSnapshotBeforeUpdate(prevProps, prevState)
componentWillReceiveProps(nextProps)
useState()
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>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
React Hooks Lifecycle
Життєвий цикл функціональних компонентів
Монтування компонента
- First react run lazy initialisers
- First render
- React updates DOM
- Run LayoutEffects
- Browser is painting the screen
- Run Effects
Оновлення компонента
- Render
- React updates DOM
- Cleanup LayoutEffects
- Run LayoutEffects
- Browser is painting the screen
- Cleanup Effects
- Run Effects
Демонтування компонента
- Clean up LayoutEffects
- Clean up Effects
Використання useEffect hook
Використання useEffect hook
/* Run only on mounting */
React.useEffect(() => {
// function body
}, []);
/* Run on props/state update */
React.useEffect(() => {
// it will be called only when "exampleProp" changes
}, [exampleProp]);
React.useEffect(() => {
// it will be called for every component update
});
/* Unmount */
React.useEffect(() => {
return () => {
// unsubscribe
}
}, ]);
React.useEffect(() => {
return () => {
// unsubscribe
// this cleanup function will be triggered on each dependency change
}
}, [dependency]);
Hooks
Built-in React Hooks
Hooks дозволяють використовувати різні функції React із ваших компонентів. Ви можете використовувати вбудовані хуки або комбінувати їх для створення власних. На цій сторінці перераховані всі вбудовані хуки в React.
function ImageGallery() {
const [index, setIndex] = useState(0);
// ...
State Hooks
Щоб додати стан до компонента, скористайтеся одним із цих хуків:
- useState оголошує змінну стану, яку можна оновити безпосередньо.
- useReducer оголошує змінну стану з логікою оновлення всередині функції редюсера.
function ImageGallery() {
const [index, setIndex] = useState(0);
// ...
Context Hooks
Контекст дозволяє компоненту отримувати інформацію від віддалених батьків, не передаючи її як атрибути. Наприклад, компонент верхнього рівня вашої програми може передавати поточну тему інтерфейсу користувача всім компонентам нижче, незалежно від глибини.
function Button() {
const theme = useContext(ThemeContext);
// ...
- useContext читає контекст і підписується на нього.
Ref Hooks
Посилання дозволяють компоненту зберігати деяку інформацію, яка не використовується для відтворення, як-от вузол DOM або ідентифікатор часу очікування. На відміну від стану, оновлення посилання не відтворює повторно ваш компонент. Refs — це «аварійний люк» із парадигми React. Вони корисні, коли вам потрібно працювати з системами, не пов’язаними з React, такими як вбудовані API браузера.
- useRef оголошує посилання. У ньому можна зберігати будь-яке значення, але найчастіше воно використовується для зберігання вузла DOM
- useImperativeHandle (рідко використовується)
function Form() {
const inputRef = useRef(null);
// ...
Effect Hooks
Ефекти дозволяють компоненту підключатися до зовнішніх систем і синхронізуватися з ними. Це включає роботу з мережею, DOM браузера, анімаціями, віджетами, написаними з використанням іншої бібліотеки інтерфейсу користувача, та іншим кодом, не пов’язаним з React.
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]);
// ...
- useEffect підключає компонент до зовнішньої системи
Performance Hooks
Поширений спосіб оптимізації продуктивності повторного рендерингу – це пропуск непотрібної роботи. Наприклад, React може повторно використовувати кешований обчислення або пропустити повторну візуалізацію, якщо дані не змінилися з часу попередньої візуалізації.
Щоб пропустити обчислення та непотрібне повторне рендеринг, скористайтеся одним із цих хуків:
- useMemo дозволяє кешувати результат дорогого обчислення
- useCallback дозволяє кешувати визначення функції перед передачею її оптимізованому
function TodoList({ todos, tab, theme }) {
const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);
// ...
}
Performance Hooks
import { useCallback } from 'react';
export default function ProductPage({ productId, referrer, theme }) {
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]);
Власні Hooks
import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";
const Home = () => {
const [data, setData] = useState(null);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos")
.then((res) => res.json())
.then((data) => setData(data));
}, []);
return (
<>
{data &&
data.map((item) => {
return <p key={item.id}>{item.title}</p>;
})}
</>
);
};
Логіку пов'язану із запитами можна перевикористати
Власні Hooks
import { useState, useEffect } from "react";
// custom hook
const useFetch = (url) => {
const [data, setData] = useState(null);
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((data) => setData(data));
}, [url]);
return [data];
};
// component
const Home = () => {
const [data] = useFetch("https://jsonplaceholder.typicode.com/todos");
return (
<>
{data &&
data.map((item) => {
return <p key={item.id}>{item.title}</p>;
})}
</>
);
};
Рендеринг з умовами
Відображення компонентів за умовами
Досить часто потрібно додавати умову, коли потрібно відображувати компонент. Наприклад під час завантаження даних, бажано відображувати "лоадер":
1
2
3
4
5
6
Відображення "лоадера"
import { useState, useEffect } from 'react';
import useFetch from '../utils/useFetch';
import Loader from './Loader'; // component with a loader
const Home = () => {
const [data] = useFetch("https://jsonplaceholder.typicode.com/todos");
return (
<>
{!data
? <Loader />
: data.map((item) => {
return <p key={item.id}>{item.title}</p>;
})}
</>
);
};
Приховування компоненту, якщо немає прав
import { useState, useEffect } from 'react';
import useFetch from '../utils/useFetch';
import Account from './Account';
import EditAccountButton from './EditAccountButton';
const Home = props => {
const hasPermissions = props.roles.includes(role => role === 'editAccount');
return (
<div>
<Account />
{ hasPermission && <EditAccountButton />}
</div>
);
};
Component
import React from 'react';
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
export default Welcome;
Компоненти дозволяють розділити інтерфейс на незалежні частини, які можна багаторазово використовувати, і розглядати кожну частину окремо.
Концептуально компоненти схожі на функції JavaScript. Вони приймають довільні вхідні дані (так звані «props») і повертають елементи React, які описують те, що має з’явитися на екрані.
Опрацювання подій
Події в React
<button onClick={activateLasers}>
Activate Lasers
</button>
Обробка подій з елементами React дуже схожа на обробку подій елементів DOM. Є деякі синтаксичні відмінності:
- Події React називаються в верблюжому регістрі, а не в нижньому регістрі.
- За допомогою JSX ви передаєте функцію як обробник події, а не рядок.
Наприклад, HTML:
і те, як потрібно в React:
<button onclick="activateLasers()">
Activate Lasers
</button>
Події в React
function Form() {
function handleSubmit(e) {
e.preventDefault();
console.log('You clicked submit.');
}
return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
Події в React: класовий компонент
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
Робота з формами
Робота з формами
import { useState } from 'react';
function MyForm() {
const [name, setName] = useState("");
const handleSubmit = (event) => {
event.preventDefault();
alert(`The name you entered was: ${name}`)
}
return (
<form onSubmit={handleSubmit}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<input type="submit" />
</form>
)
}
Робота з формами: multiple inputs
import { useState } from 'react';
import ReactDOM from 'react-dom/client';
function MyForm() {
const [inputs, setInputs] = useState({});
const handleChange = (event) => {
const name = event.target.name;
const value = event.target.value;
setInputs(values => ({...values, [name]: value}))
}
const handleSubmit = (event) => {
event.preventDefault();
alert(inputs);
}
return (
<form onSubmit={handleSubmit}>
<label>Enter your name:
<input
type="text"
name="username"
value={inputs.username || ""}
onChange={handleChange}
/>
</label>
<label>Enter your age:
<input
type="number"
name="age"
value={inputs.age || ""}
onChange={handleChange}
/>
</label>
<input type="submit" />
</form>
)
}
Робота з формами: класові компоненти
class EssayForm extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 'Please write an essay about your favorite DOM element.'
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('An essay was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Essay:
<textarea value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
npm
npm install
npm add [package] --save-dev # dev dependencies
npm add [package] # dependencies
npm — це менеджер пакетів для мови програмування JavaScript, який підтримується npm, Inc. npm — це менеджер пакетів за замовчуванням для середовища виконання JavaScript Node.js.
Він складається з командного рядка клієнта, який також називається npm, і онлайнової бази даних загальнодоступних і платних приватних пакетів, яка називається реєстром npm.
yarn/npm та package.json
npm run start
Для того, щоб запустити застосунок необхідно використати наступну npm команду:
yarn start
Або використати yarn:
yarn/npm та package.json
{
"name": "first-react-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Всі доступні команди, а також набір залежностей описаний в package.json
Всі встановлені залежності будуть доступні в директорії node_modules
yarn/npm та package.json
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Команда build дозволяє отримати фінальний результат, який можна розмістити на хостингу або інших ресурсах
yarn build
Робота з HTTP запитами
import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";
const Home = () => {
const [data, setData] = useState(null);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos")
.then((res) => res.json())
.then((data) => setData(data));
}, []);
return (
<>
{data &&
data.map((item) => {
return <p key={item.id}>{item.title}</p>;
})}
</>
);
};
useEffect та useState
Q & A
_14 JavaScript Crash Course: React
By Inna Ivashchuk
_14 JavaScript Crash Course: React
- 294