<!DOCTYPE html>
<html class="h-100" data-bs-theme="light" data-mantine-color-scheme="light" lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<link crossorigin="true" href="https://cdn.hexlet.io" rel="preconnect">
<meta content="aa2vrdtq64dub8knuf83lwywit311w" name="facebook-domain-verification">
<link href="/favicon.ico" rel="icon" sizes="any">
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<link href="/apple-touch-icon.png" rel="apple-touch-icon">
<link href="/manifest.webmanifest" rel="manifest">
<script>
//<![CDATA[
window.gon={};gon.ym_counter="25559621";gon.is_bot=true;gon.applications={};gon.current_user={"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false};gon.token="f_SPGR6ZggEiIPDZWBakuwOpZaYcPwnXvjyv-UQDP5QsMuIvP_K54UUqDzHqiJN6DwPr_dAhE9scuWXqCd_gTw";gon.locale="en";gon.language="en";gon.theme="light";gon.rails_env="production";gon.mobile=false;gon.google={"analytics_key":"UA-1360700-51","optimize_key":"GTM-5QDVFPF"};gon.captcha={"google_v3_site_key":"6LenGbgZAAAAAM7HbrDbn5JlizCSzPcS767c9vaY","yandex_site_key":"ysc1_Vyob5ZPPUdPBsu0ykt8bVFdzsfpoVjQChLGl2b4g19647a89","verification_failed":null};gon.social_signin=false;gon.typoreporter_google_form_id="1FAIpQLScNwxM8rjQRRWqW5G6dn6-0NvLUblFemy7EvA9VsJ7Ov5wXqA";
//]]>
</script>
<meta charset="utf-8">
<title>Course «JS: React Hooks»: online education</title>
<meta name="description" content="Take the JS: React Hooks course at the Hexlet online school. Experienced mentors, practice on simulators, open-source projects in your portfolio. Individual and group online learning at Hexlet.">
<link rel="canonical" href="https://hexlet.io/courses/js-react-hooks">
<meta property="og:description" content="Take the JS: React Hooks course at the Hexlet online school. Experienced mentors, practice on simulators, open-source projects in your portfolio. Individual and group online learning at Hexlet.
">
<meta property="og:title" content="Course «JS: React Hooks»: online education
">
<meta property="og:url" content="https://hexlet.io/courses/js-react-hooks">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="-glSVN3jh-m7NqbMOYC8rt6pRN9apTR0sztvviK370qpzz9i_Ii8Cdw8WSSLHotv0gPKhJa7LngRvqWtb2swkQ" />
<script src="/vite/assets/inertia-CgrHVkgd.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/preload-helper-C1cfMHAs.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-0bhwJkNI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ahoy-BXKrsWjp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/analytics-Du9ljYPK.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-V3hfk_CP.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/RootLayout-CUZzAr0T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Surface-DbDKujDz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-B-jV56Ol.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-DOJkeu70.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-ClTF9s_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-mvvEXZQ8.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/index.esm-DATLpQdV.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Modal-BhY0AP_c.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Textarea-P1s4q94S.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/exports-BsSGGK2I.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-Bfba02I7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-CYyKzrjQ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-SJZekO2j.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-bo78L81P.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-BhqaZ6vG.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-DlXMvSuQ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CFtMU8gd.js" as="script" crossorigin="anonymous">
<link rel="stylesheet" href="/vite/assets/application-BhDYOUva.css" />
<script src="/vite/assets/application-ZyVHkzwO.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/autocomplete-BokUl44d.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-mvvEXZQ8.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/createPopper-gQnwoPhY.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/js.cookie-CB1F2-VC.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="/vite/assets/application-BhDYOUva.css" media="screen" />
<!-- Google Tag Manager - deferred -->
<script>
// dataLayer stub сразу — пуши работают до загрузки скрипта
window.dataLayer = window.dataLayer || [];
// Сам скрипт — отложенно после load
window.addEventListener('load', function() {
setTimeout(function() {
dataLayer.push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var j = document.createElement('script');
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-WK88TH';
document.head.appendChild(j);
}, 1500);
});
</script>
<!-- End Google Tag Manager -->
</head>
<body>
<!-- Google Tag Manager (noscript) -->
<noscript>
<iframe height="0" src="https://www.googletagmanager.com/ns.html?id=GTM-WK88TH" style="display:none;visibility:hidden" width="0"></iframe>
</noscript>
<!-- End Google Tag Manager (noscript) -->
<header class="sticky-top bg-body">
<nav class="navbar navbar-expand-lg">
<div class="container-xxl">
<a class="navbar-brand" href="/"><img alt="Hexlet logo" height="24" src="https://hexlet.io/vite/assets/logo_en_light-FS-yL6XB.svg" width="96">
</a><button aria-controls="collapsable" aria-expanded="false" aria-label="Menu" class="navbar-toggler border-0 mb-0 mt-1" data-bs-target="#collapsable" data-bs-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsable">
<ul class="navbar-nav mb-lg-0 mt-lg-1">
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
All courses
<span class="bi bi-chevron-down align-middle ms-1"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item d-flex py-2" href="/courses"><div class="fw-bold me-auto">Everything</div>
<div class="text-muted">8</div>
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Popular categories</b>
</li>
<li>
<a class="dropdown-item py-2" href="/courses_backend-development">Backend Development
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_devops">DevOps
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_frontend-development">Frontend Development
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_testing">Testing
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Popular courses</b>
</li>
<li>
<a class="dropdown-item py-2" href="/programs/frontend">Frontend Developer
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
About Hexlet
<span class="bi bi-chevron-down align-middle"></span>
</button>
<ul class="dropdown-menu bg-body">
<li>
<a class="dropdown-item py-2" href="/pages/about">About company
</a></li>
<li>
<a class="dropdown-item py-2" href="/blog">Blog
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/hse-research" role="button"><span class="translation_missing" title="translation missing: en.layouts.header.results">Results</span>
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://career.hexlet.io" role="button"><span class="translation_missing" title="translation missing: en.layouts.header.career">Career</span>
</span></li>
<li>
<a class="dropdown-item py-2" href="/testimonials">Testimonials
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://t.me/hexlet_help_bot" role="button"><span class="translation_missing" title="translation missing: en.layouts.header.support">Support</span>
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/referal-program/?promo_creative=priglasite-druzei&promo_name=referal-program&promo_position=promo_position&promo_start=010724&promo_type=link" role="button"><span class="translation_missing" title="translation missing: en.layouts.header.referal_program">Referal Program</span>
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/certificate" role="button"><span class="translation_missing" title="translation missing: en.layouts.header.certificates">Certificates</span>
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://hh.ru/employer/4307094" role="button"><span class="translation_missing" title="translation missing: en.layouts.header.vacancies">Vacancies</span>
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://b2b.hexlet.io" data-target="_blank" role="button"><span class="translation_missing" title="translation missing: en.layouts.header.teams">Teams</span>
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexly.ru/" data-target="_blank" role="button"><span class="translation_missing" title="translation missing: en.layouts.header.college">College</span>
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexlyschool.ru/" data-target="_blank" role="button"><span class="translation_missing" title="translation missing: en.layouts.header.private_school">Private School</span>
</span></li>
</ul>
</li>
</ul>
<ul class="navbar-nav flex-lg-row align-items-lg-center gap-2 ms-auto">
<li>
<a class="nav-link" aria-label="Switch theme" href="/theme/switch?new_theme=dark"><span aria-hidden="true" class="bi bi-moon"></span>
</a></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="/u/new" role="button"><span>Sign up</span>
</span></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="https://hexlet.io/session/new" role="button"><span>Sign in</span>
</span></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="x-container-xxxl">
</div>
<main class="mb-6 min-vh-100 h-100">
<link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTIzNTMsInB1ciI6ImJsb2JfaWQifX0=--f1948fb0c5a45a6d76671a1a32b8cf6f0b53ee57/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Software%20code%20testing-cuate.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTIzNTAsInB1ciI6ImJsb2JfaWQifX0=--4c31372fe7c51ddbc0ef0d54fe47eaba88a2b04b/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programmer-rafiki.png"/><link rel="preload" as="image" href="/vite/assets/development-BVihs_d5.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NzUyMCwicHVyIjoiYmxvYl9pZCJ9fQ==--f0a2dddfa33850502cb3a06e6fa6b2cf1f8a077d/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJwbmciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--6067466c2912ca31a17eddee04b8cf2a38c6ad17/image.png"/><div id="app" data-page="{"component":"web/courses/show","props":{"errors":{},"locale":"en","language":"en","httpsHost":"https://hexlet.io","host":"hexlet.io","colorScheme":"light","auth":{"user":{"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false}},"cloudflareTurnstileSiteKey":"0x4AAAAAAA15KmeFXzd2H0Xo","vkIdClientId":"51586979","yandexIdClientId":null,"formAuthToken":"oDGj1DeXuwa71ezUhclrEGIxefKz-dfsLl3M_kPxc7Tz987iFvyA5tzfEzw3V1zRbpv3qX_nzeCM2AbtDi2sbw","course":{"start_lesson":{"exercise":null,"units":[{"id":7890,"name":"theory","url":"/courses/js-react-hooks/lessons/intro/theory_unit"}],"links":[{"id":424305,"name":"Plugin eslint-plugin-react-hooks","url":"https://www.npmjs.com/package/eslint-plugin-react-hooks#installation"}],"ordered_units":[{"id":7890,"name":"theory","url":"/courses/js-react-hooks/lessons/intro/theory_unit"}],"id":3539,"slug":"intro","state":"approved","name":"Introduction","course_order":100,"goal":"Learning about the course and set up an environment","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"\n\nHooks are a mechanism in React that allows you to work without classes. It doesn't add anything new, but it simplifies code reuse to solve frequent problems.\n\nCurrently, this is the main way to write React applications. But hooks don't replace classes entirely. Moreover, the React team doesn't plan to remove support for classes. And you can do something without classes. An example of how the `useState` hook works for storing the state:\n\n```jsx\n// useState – built-in React hook\n// To be discussed in more detail in the next lesson\nimport React, { useState } from 'react';\n\nconst Example = () => {\n // It is the example of a hook for working with the state\n const [count, setCount] = useState(0);\n\n return (\n <div>\n <p>You clicked {count} time(s)</p>\n <button onClick={() => setCount(count + 1)}>\n Click me\n </button>\n </div>\n );\n};\n```\n\n<!---<p class=\"codepen\" data-height=\"300\" data-default-tab=\"js,result\" data-slug-hash=\"WNZvQqW\" data-user=\"hexlet\" style=\"height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\">\n <span>See the Pen <a href=\"https://codepen.io/hexlet/pen/WNZvQqW\">\n js_react_hooks_use_effect-1</a> by Hexlet (<a href=\"https://codepen.io/hexlet\">@hexlet</a>)\n on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://cpwebassets.codepen.io/assets/embed/ei.js\"></script>--->\n\nHooks are functions with names usually beginning with `use` so they are easy to distinguish. React has about ten hooks built in, only a few of which programmers use regularly. The main ones repeat the functionality of class components, such as working with state, side effects (lifecycle), context, and direct access to the Dom. We'll look at them throughout the course. You can find information on the remaining hooks in the official documentation.\n\nIn addition to the built-in ones, you can find hundreds, if not thousands, of ready-made hooks for all purposes on the web. For example, the popular [react-use](https://github.com/streamich/react-use) has more than 115 hooks. Now, development in React has turned into the search and use of suitable hooks. It is good because you can focus on your tasks and worry less about inventing bicycles.\n"},"id":337,"slug":"js-react-hooks","challenges_count":4,"name":"JS: React Hooks","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"React Hooks is a mechanism that allows building applications without classes, only on functional components. Thanks to hooks, the code becomes smaller, and the level of code reuse becomes higher.","kind":"advanced","updated_at":"2026-01-20T11:46:21.369Z","language":"javascript","duration_cache":19740,"skills":["Use built-in hooks","Create an application consisting of functional components","Implement ready-made hooks for solving typical tasks"],"keywords":[],"lessons_count":5,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NzUyMCwicHVyIjoiYmxvYl9pZCJ9fQ==--f0a2dddfa33850502cb3a06e6fa6b2cf1f8a077d/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJwbmciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--6067466c2912ca31a17eddee04b8cf2a38c6ad17/image.png"},"courseMember":null,"questionsCount":14,"exercisesCount":4,"lessons":[{"ordered_units":[{"id":7890,"name":"theory","url":"/courses/js-react-hooks/lessons/intro/theory_unit"}],"id":3539,"slug":"intro","state":"approved","name":"Introduction","course_order":100,"goal":"Learning about the course and set up an environment","exercise_id":null},{"ordered_units":[{"id":7891,"name":"theory","url":"/courses/js-react-hooks/lessons/use-state/theory_unit"},{"id":8190,"name":"quiz","url":"/courses/js-react-hooks/lessons/use-state/quiz_unit"},{"id":8278,"name":"exercise","url":"/courses/js-react-hooks/lessons/use-state/exercise_unit"}],"id":3540,"slug":"use-state","state":"approved","name":"useState Hook","course_order":200,"goal":"Exploring how hooks work and learn the most basic one, which is responsible for managing state","exercise_id":2384},{"ordered_units":[{"id":7892,"name":"theory","url":"/courses/js-react-hooks/lessons/use-effect/theory_unit"},{"id":8191,"name":"quiz","url":"/courses/js-react-hooks/lessons/use-effect/quiz_unit"},{"id":8279,"name":"exercise","url":"/courses/js-react-hooks/lessons/use-effect/exercise_unit"}],"id":3541,"slug":"use-effect","state":"approved","name":"useEffect Hook","course_order":300,"goal":"Learning how to properly isolate side effects with hooks","exercise_id":2385},{"ordered_units":[{"id":7893,"name":"theory","url":"/courses/js-react-hooks/lessons/use-context/theory_unit"},{"id":8192,"name":"quiz","url":"/courses/js-react-hooks/lessons/use-context/quiz_unit"},{"id":8277,"name":"exercise","url":"/courses/js-react-hooks/lessons/use-context/exercise_unit"}],"id":3542,"slug":"use-context","state":"approved","name":"useContext Hook","course_order":400,"goal":"Learning to work with context through hooks","exercise_id":2386},{"ordered_units":[{"id":7894,"name":"theory","url":"/courses/js-react-hooks/lessons/use-ref/theory_unit"},{"id":8193,"name":"quiz","url":"/courses/js-react-hooks/lessons/use-ref/quiz_unit"},{"id":8276,"name":"exercise","url":"/courses/js-react-hooks/lessons/use-ref/exercise_unit"}],"id":3543,"slug":"use-ref","state":"approved","name":"useRef Hook","course_order":500,"goal":"Learning how to access DOM elements with hooks","exercise_id":2387}],"challenges":[{"exercise":{"id":2388,"slug":"js_react_counting_buttons_exercise","name":"Don't touch me","state":"active","kind":"challenge","language":"javascript","locale":"en","has_web_view":true,"has_test_view":false,"reviewable":true,"readme":"### Buttons.jsx\n\nImplement the `<Buttons/>` component and export it as default. It should render the buttons with the counter value.\n\nThe component should have the following logic:\n\n* The current counter value of each button is a string inside the _button_ tag.\n* Clicking on the button should increase the counter value by one, without affecting other counters\n* The component must take the `count` prop that specifies the number of buttons (3 by default)\n* To style the buttons, use the _bootstrap_ library (you can import it in your component)\n* The last clicked button changes color (via class change). The classes are given in the below examples\n\n### Examples\n\nButtons with a zero counter value:\n\n```html\n<button class=\"btn btn-primary m-1\" type=\"button\">0</button>\n<button class=\"btn btn-primary m-1\" type=\"button\">0</button>\n<button class=\"btn btn-primary m-1\" type=\"button\">0</button>\n```\n\nThe clicked buttons. The last one was the second one (btn-primary => btn-success):\n\n```html\n<button class=\"btn btn-primary m-1\" type=\"button\">3</button>\n<button class=\"btn btn-success m-1\" type=\"button\">1</button>\n<button class=\"btn btn-primary m-1\" type=\"button\">2</button>\n```\n\n### Tips\n\n* Solve this task using functional components and hooks\n* Use the [useImmer](https://github.com/immerjs/use-immer) hook to manage a state\n* [The Rise of Immer in React](https://www.netlify.com/blog/2018/09/12/the-rise-of-immer-in-react/)\n* React docs on [hooks](https://beta.reactjs.org/reference/react)\n","prepared_readme":"### Buttons.jsx\n\nImplement the `<Buttons/>` component and export it as default. It should render the buttons with the counter value.\n\nThe component should have the following logic:\n\n* The current counter value of each button is a string inside the _button_ tag.\n* Clicking on the button should increase the counter value by one, without affecting other counters\n* The component must take the `count` prop that specifies the number of buttons (3 by default)\n* To style the buttons, use the _bootstrap_ library (you can import it in your component)\n* The last clicked button changes color (via class change). The classes are given in the below examples\n\n### Examples\n\nButtons with a zero counter value:\n\n```html\n<button class=\"btn btn-primary m-1\" type=\"button\">0</button>\n<button class=\"btn btn-primary m-1\" type=\"button\">0</button>\n<button class=\"btn btn-primary m-1\" type=\"button\">0</button>\n```\n\nThe clicked buttons. The last one was the second one (btn-primary => btn-success):\n\n```html\n<button class=\"btn btn-primary m-1\" type=\"button\">3</button>\n<button class=\"btn btn-success m-1\" type=\"button\">1</button>\n<button class=\"btn btn-primary m-1\" type=\"button\">2</button>\n```\n\n### Tips\n\n* Solve this task using functional components and hooks\n* Use the [useImmer](https://github.com/immerjs/use-immer) hook to manage a state\n* [The Rise of Immer in React](https://www.netlify.com/blog/2018/09/12/the-rise-of-immer-in-react/)\n* React docs on [hooks](https://beta.reactjs.org/reference/react)\n","has_solution":true,"entity_name":"Don't touch me"},"course":{"start_lesson":{"exercise":null,"units":[{"id":7890,"name":"theory","url":"/courses/js-react-hooks/lessons/intro/theory_unit"}],"links":[{"id":424305,"name":"Plugin eslint-plugin-react-hooks","url":"https://www.npmjs.com/package/eslint-plugin-react-hooks#installation"}],"ordered_units":[{"id":7890,"name":"theory","url":"/courses/js-react-hooks/lessons/intro/theory_unit"}],"id":3539,"slug":"intro","state":"approved","name":"Introduction","course_order":100,"goal":"Learning about the course and set up an environment","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"\n\nHooks are a mechanism in React that allows you to work without classes. It doesn't add anything new, but it simplifies code reuse to solve frequent problems.\n\nCurrently, this is the main way to write React applications. But hooks don't replace classes entirely. Moreover, the React team doesn't plan to remove support for classes. And you can do something without classes. An example of how the `useState` hook works for storing the state:\n\n```jsx\n// useState – built-in React hook\n// To be discussed in more detail in the next lesson\nimport React, { useState } from 'react';\n\nconst Example = () => {\n // It is the example of a hook for working with the state\n const [count, setCount] = useState(0);\n\n return (\n <div>\n <p>You clicked {count} time(s)</p>\n <button onClick={() => setCount(count + 1)}>\n Click me\n </button>\n </div>\n );\n};\n```\n\n<!---<p class=\"codepen\" data-height=\"300\" data-default-tab=\"js,result\" data-slug-hash=\"WNZvQqW\" data-user=\"hexlet\" style=\"height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\">\n <span>See the Pen <a href=\"https://codepen.io/hexlet/pen/WNZvQqW\">\n js_react_hooks_use_effect-1</a> by Hexlet (<a href=\"https://codepen.io/hexlet\">@hexlet</a>)\n on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://cpwebassets.codepen.io/assets/embed/ei.js\"></script>--->\n\nHooks are functions with names usually beginning with `use` so they are easy to distinguish. React has about ten hooks built in, only a few of which programmers use regularly. The main ones repeat the functionality of class components, such as working with state, side effects (lifecycle), context, and direct access to the Dom. We'll look at them throughout the course. You can find information on the remaining hooks in the official documentation.\n\nIn addition to the built-in ones, you can find hundreds, if not thousands, of ready-made hooks for all purposes on the web. For example, the popular [react-use](https://github.com/streamich/react-use) has more than 115 hooks. Now, development in React has turned into the search and use of suitable hooks. It is good because you can focus on your tasks and worry less about inventing bicycles.\n"},"id":337,"slug":"js-react-hooks","challenges_count":4,"name":"JS: React Hooks","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"React Hooks is a mechanism that allows building applications without classes, only on functional components. Thanks to hooks, the code becomes smaller, and the level of code reuse becomes higher.","kind":"advanced","updated_at":"2026-01-20T11:46:21.369Z","language":"javascript","duration_cache":19740,"skills":["Use built-in hooks","Create an application consisting of functional components","Implement ready-made hooks for solving typical tasks"],"keywords":[],"lessons_count":5,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NzUyMCwicHVyIjoiYmxvYl9pZCJ9fQ==--f0a2dddfa33850502cb3a06e6fa6b2cf1f8a077d/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJwbmciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--6067466c2912ca31a17eddee04b8cf2a38c6ad17/image.png"},"id":672,"slug":"js_react_counting_buttons_exercise","percent_of_success":"-"},{"exercise":{"id":2391,"slug":"js_react_hooks_table_sort_exercise","name":"Table","state":"active","kind":"challenge","language":"javascript","locale":"en","has_web_view":true,"has_test_view":false,"reviewable":true,"readme":"In this task, you will implement a table that can be sorted by columns.\n\nThe list with objects is passed as data via `props`. You need to output a table where each column will point to a value in the object. Clicking on a column heading sorts the table. First click sorts in ascending order, second click sorts in descending order. Sorting is performed for one column only. By default, the list is displayed in the order in which it arrived.\n\nThe objects themselves can have any flat structure, which means that their keys can be different.\n\nExample of data:\n\n```javascript\nconst list = [\n { id: 1, firstName: 'Amaya', lastName: 'Torphy', jobTitle: 'Legacy Group Facilitator', email: 'Rosie_Mann@gmail.com' },\n { id: 2, firstName: 'Weston', lastName: 'Huel', jobTitle: 'Regional Data Agent', email: 'Tristian_Vandervort68@yahoo.com' },\n { id: 3, firstName: 'Bridgette', lastName: 'Corwin', jobTitle: 'Internal Usability Officer', email: 'Sherman.Purdy@hotmail.com' },\n];\n```\n\nExample of table:\n\n```html\n<table class=\"table\">\n <thead>\n <tr>\n <th>id</th>\n <th>firstName</th>\n <th>lastName</th>\n <th>jobTitle</th>\n <th>email</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>1</td>\n <td>Amaya</td>\n <td>Torphy</td>\n <td>Legacy Group Facilitator</td>\n <td>Rosie_Mann@gmail.com</td>\n </tr>\n <tr>\n <td>2</td>\n <td>Weston</td>\n <td>Huel</td>\n <td>Regional Data Agent</td>\n <td>Tristian_Vandervort68@yahoo.com</td>\n </tr>\n <tr>\n <td>3</td>\n <td>Bridgette</td>\n <td>Corwin</td>\n <td>Internal Usability Officer</td>\n <td>Sherman.Purdy@hotmail.com</td>\n </tr>\n </tbody>\n</table>\n```\n## src/App.jsx\n\nImplement a table\n\n## Hints\n\n* You can use [bootstrap component](https://react-bootstrap.github.io/components/table/)","prepared_readme":"In this task, you will implement a table that can be sorted by columns.\n\nThe list with objects is passed as data via `props`. You need to output a table where each column will point to a value in the object. Clicking on a column heading sorts the table. First click sorts in ascending order, second click sorts in descending order. Sorting is performed for one column only. By default, the list is displayed in the order in which it arrived.\n\nThe objects themselves can have any flat structure, which means that their keys can be different.\n\nExample of data:\n\n```javascript\nconst list = [\n { id: 1, firstName: 'Amaya', lastName: 'Torphy', jobTitle: 'Legacy Group Facilitator', email: 'Rosie_Mann@gmail.com' },\n { id: 2, firstName: 'Weston', lastName: 'Huel', jobTitle: 'Regional Data Agent', email: 'Tristian_Vandervort68@yahoo.com' },\n { id: 3, firstName: 'Bridgette', lastName: 'Corwin', jobTitle: 'Internal Usability Officer', email: 'Sherman.Purdy@hotmail.com' },\n];\n```\n\nExample of table:\n\n```html\n<table class=\"table\">\n <thead>\n <tr>\n <th>id</th>\n <th>firstName</th>\n <th>lastName</th>\n <th>jobTitle</th>\n <th>email</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <td>1</td>\n <td>Amaya</td>\n <td>Torphy</td>\n <td>Legacy Group Facilitator</td>\n <td>Rosie_Mann@gmail.com</td>\n </tr>\n <tr>\n <td>2</td>\n <td>Weston</td>\n <td>Huel</td>\n <td>Regional Data Agent</td>\n <td>Tristian_Vandervort68@yahoo.com</td>\n </tr>\n <tr>\n <td>3</td>\n <td>Bridgette</td>\n <td>Corwin</td>\n <td>Internal Usability Officer</td>\n <td>Sherman.Purdy@hotmail.com</td>\n </tr>\n </tbody>\n</table>\n```\n## src/App.jsx\n\nImplement a table\n\n## Hints\n\n* You can use [bootstrap component](https://react-bootstrap.github.io/components/table/)","has_solution":true,"entity_name":"Table"},"course":{"start_lesson":{"exercise":null,"units":[{"id":7890,"name":"theory","url":"/courses/js-react-hooks/lessons/intro/theory_unit"}],"links":[{"id":424305,"name":"Plugin eslint-plugin-react-hooks","url":"https://www.npmjs.com/package/eslint-plugin-react-hooks#installation"}],"ordered_units":[{"id":7890,"name":"theory","url":"/courses/js-react-hooks/lessons/intro/theory_unit"}],"id":3539,"slug":"intro","state":"approved","name":"Introduction","course_order":100,"goal":"Learning about the course and set up an environment","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"\n\nHooks are a mechanism in React that allows you to work without classes. It doesn't add anything new, but it simplifies code reuse to solve frequent problems.\n\nCurrently, this is the main way to write React applications. But hooks don't replace classes entirely. Moreover, the React team doesn't plan to remove support for classes. And you can do something without classes. An example of how the `useState` hook works for storing the state:\n\n```jsx\n// useState – built-in React hook\n// To be discussed in more detail in the next lesson\nimport React, { useState } from 'react';\n\nconst Example = () => {\n // It is the example of a hook for working with the state\n const [count, setCount] = useState(0);\n\n return (\n <div>\n <p>You clicked {count} time(s)</p>\n <button onClick={() => setCount(count + 1)}>\n Click me\n </button>\n </div>\n );\n};\n```\n\n<!---<p class=\"codepen\" data-height=\"300\" data-default-tab=\"js,result\" data-slug-hash=\"WNZvQqW\" data-user=\"hexlet\" style=\"height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\">\n <span>See the Pen <a href=\"https://codepen.io/hexlet/pen/WNZvQqW\">\n js_react_hooks_use_effect-1</a> by Hexlet (<a href=\"https://codepen.io/hexlet\">@hexlet</a>)\n on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://cpwebassets.codepen.io/assets/embed/ei.js\"></script>--->\n\nHooks are functions with names usually beginning with `use` so they are easy to distinguish. React has about ten hooks built in, only a few of which programmers use regularly. The main ones repeat the functionality of class components, such as working with state, side effects (lifecycle), context, and direct access to the Dom. We'll look at them throughout the course. You can find information on the remaining hooks in the official documentation.\n\nIn addition to the built-in ones, you can find hundreds, if not thousands, of ready-made hooks for all purposes on the web. For example, the popular [react-use](https://github.com/streamich/react-use) has more than 115 hooks. Now, development in React has turned into the search and use of suitable hooks. It is good because you can focus on your tasks and worry less about inventing bicycles.\n"},"id":337,"slug":"js-react-hooks","challenges_count":4,"name":"JS: React Hooks","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"React Hooks is a mechanism that allows building applications without classes, only on functional components. Thanks to hooks, the code becomes smaller, and the level of code reuse becomes higher.","kind":"advanced","updated_at":"2026-01-20T11:46:21.369Z","language":"javascript","duration_cache":19740,"skills":["Use built-in hooks","Create an application consisting of functional components","Implement ready-made hooks for solving typical tasks"],"keywords":[],"lessons_count":5,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NzUyMCwicHVyIjoiYmxvYl9pZCJ9fQ==--f0a2dddfa33850502cb3a06e6fa6b2cf1f8a077d/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJwbmciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--6067466c2912ca31a17eddee04b8cf2a38c6ad17/image.png"},"id":675,"slug":"js_react_hooks_table_sort_exercise","percent_of_success":"-"},{"exercise":{"id":2389,"slug":"js_react_modals_exercise","name":"Modal windows","state":"active","kind":"challenge","language":"javascript","locale":"en","has_web_view":true,"has_test_view":false,"reviewable":true,"readme":"## App.jsx\n\nImplement and export as default the component that represents the notebook application.\n\nIn this application, you can add, delete, and edit tasks using modal windows. Each action produces a modal window where you can perform different actions.\n\nTo complete the challenge, you will need to master new hooks and use built-in Bootstrap components. We recommend that you take this challenge after completing the [previous](https://hexlet.io/challenges/js_react_counting_buttons_exercise).\n\n### Examples\n\nInitial HTML:\n\n```html\n<div class=\"mb-3\">\n <button type=\"button\" data-testid=\"item-add\" class=\"btn btn-secondary\">add</button>\n</div>\n```\n\nAfter clicking \"add\":\n\n```html\n<div class=\"mb-3\">\n <button type=\"button\" data-testid=\"item-add\" class=\"btn btn-secondary\">add</button>\n</div>\n<div class=\"modal-dialog\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <div class=\"modal-title h4\">Add</div>\n <button type=\"button\" class=\"btn-close\" aria-label=\"Close\"></button>\n </div>\n <div class=\"modal-body\">\n <form>\n <div class=\"form-group\">\n <input class=\"form-control\" data-testid=\"input-body\" name=\"body\" required=\"\" value=\"\" />\n </div>\n <input class=\"btn btn-primary\" type=\"submit\" value=\"submit\" />\n </form>\n </div>\n </div>\n</div>\n```\n\nAfter adding the first task:\n\n```html\n<div class=\"mb-3\">\n <button type=\"button\" data-testid=\"item-add\" class=\"btn btn-secondary\">add</button>\n</div>\n<div>\n <span class=\"mr-3\">first task!</span>\n <button type=\"button\" class=\"border-0 btn btn-link mr-3 text-decoration-none\" data-testid=\"item-rename\">rename</button>\n <button type=\"button\" class=\"border-0 btn btn-link text-decoration-none\" data-testid=\"item-remove\">remove</button>\n</div>\n```\n\nAfter clicking \"rename\":\n\n```html\n<div class=\"mb-3\">\n <button type=\"button\" data-testid=\"item-add\" class=\"btn btn-secondary\">add</button>\n</div>\n<div>\n <span class=\"mr-3\">first task!</span>\n <button type=\"button\" class=\"border-0 btn btn-link mr-3 text-decoration-none\" data-testid=\"item-rename\">rename</button>\n <button type=\"button\" class=\"border-0 btn btn-link text-decoration-none\" data-testid=\"item-remove\">remove</button>\n</div>\n<div class=\"modal-dialog\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <div class=\"modal-title h4\">Rename</div>\n <button type=\"button\" class=\"btn-close\" aria-label=\"Close\"></button>\n </div>\n <div class=\"modal-body\">\n <form>\n <div class=\"form-group\">\n <input class=\"form-control\" data-testid=\"input-body\" name=\"body\" required=\"\" value=\"first task!\" />\n </div>\n <input class=\"btn btn-primary\" type=\"submit\" value=\"submit\" />\n </form>\n </div>\n </div>\n</div>\n```\n\nAfter renaming, the previous HTML returns, but with a new name.\n\nAfter clicking \"remove\":\n\n```html\n<div class=\"mb-3\">\n <button type=\"button\" data-testid=\"item-add\" class=\"btn btn-secondary\">add</button>\n</div>\n<div>\n <span class=\"mr-3\">changed name!</span>\n <button type=\"button\" class=\"border-0 btn btn-link mr-3 text-decoration-none\" data-testid=\"item-rename\">rename</button>\n <button type=\"button\" class=\"border-0 btn btn-link text-decoration-none\" data-testid=\"item-remove\">remove</button>\n</div>\n<div class=\"modal-dialog\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <div class=\"modal-title h4\">Remove</div>\n <button type=\"button\" class=\"btn-close\" aria-label=\"Close\"></button>\n </div>\n <div class=\"modal-body\">\n <form>\n <div class=\"form-group\">\n <input class=\"btn btn-danger\" type=\"submit\" value=\"remove\" />\n </div>\n </form>\n </div>\n </div>\n</div>\n```\n\nNotebook entry disappears after removing.\n\n## modals/Add.jsx\n\nImplement a modal window for adding a task. Make sure to cast focus on the input field when the window appears. This is important for usability.\n\n## modals/Rename.jsx\n\nImplement a modal window for renaming a task. Make sure to cast focus on the input field and select the text in it when the window appears. This is important for usability.\n\n## modals/Remove.jsx\n\nImplement a modal window for removing a task.\n\n### Tips\n\n* Docs for built-in hooks: [useState](https://reactjs.org/docs/hooks-state.html), [useEffect](https://reactjs.org/docs/hooks-effect.html), [useRef](https://reactjs.org/docs/hooks-reference.html#useref)\n* Docs for third-party hooks: [useImmer](https://github.com/immerjs/use-immer), [useFormik](https://formik.org/docs/api/useFormik)\n* [React Bootstrap](https://react-bootstrap.github.io/) docs\n* `useImmer()` is used for point-by-point updates in a mutable style, while retaining the advantage of immutable data structures. It is especially suited for making changes to complex data structures, for example, when you need to find an object in a list and change its property. `useState()` is suitable for managing a simple state.\n* Layout may vary\n","prepared_readme":"## App.jsx\n\nImplement and export as default the component that represents the notebook application.\n\nIn this application, you can add, delete, and edit tasks using modal windows. Each action produces a modal window where you can perform different actions.\n\nTo complete the challenge, you will need to master new hooks and use built-in Bootstrap components. We recommend that you take this challenge after completing the [previous](https://hexlet.io/challenges/js_react_counting_buttons_exercise).\n\n### Examples\n\nInitial HTML:\n\n```html\n<div class=\"mb-3\">\n <button type=\"button\" data-testid=\"item-add\" class=\"btn btn-secondary\">add</button>\n</div>\n```\n\nAfter clicking \"add\":\n\n```html\n<div class=\"mb-3\">\n <button type=\"button\" data-testid=\"item-add\" class=\"btn btn-secondary\">add</button>\n</div>\n<div class=\"modal-dialog\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <div class=\"modal-title h4\">Add</div>\n <button type=\"button\" class=\"btn-close\" aria-label=\"Close\"></button>\n </div>\n <div class=\"modal-body\">\n <form>\n <div class=\"form-group\">\n <input class=\"form-control\" data-testid=\"input-body\" name=\"body\" required=\"\" value=\"\" />\n </div>\n <input class=\"btn btn-primary\" type=\"submit\" value=\"submit\" />\n </form>\n </div>\n </div>\n</div>\n```\n\nAfter adding the first task:\n\n```html\n<div class=\"mb-3\">\n <button type=\"button\" data-testid=\"item-add\" class=\"btn btn-secondary\">add</button>\n</div>\n<div>\n <span class=\"mr-3\">first task!</span>\n <button type=\"button\" class=\"border-0 btn btn-link mr-3 text-decoration-none\" data-testid=\"item-rename\">rename</button>\n <button type=\"button\" class=\"border-0 btn btn-link text-decoration-none\" data-testid=\"item-remove\">remove</button>\n</div>\n```\n\nAfter clicking \"rename\":\n\n```html\n<div class=\"mb-3\">\n <button type=\"button\" data-testid=\"item-add\" class=\"btn btn-secondary\">add</button>\n</div>\n<div>\n <span class=\"mr-3\">first task!</span>\n <button type=\"button\" class=\"border-0 btn btn-link mr-3 text-decoration-none\" data-testid=\"item-rename\">rename</button>\n <button type=\"button\" class=\"border-0 btn btn-link text-decoration-none\" data-testid=\"item-remove\">remove</button>\n</div>\n<div class=\"modal-dialog\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <div class=\"modal-title h4\">Rename</div>\n <button type=\"button\" class=\"btn-close\" aria-label=\"Close\"></button>\n </div>\n <div class=\"modal-body\">\n <form>\n <div class=\"form-group\">\n <input class=\"form-control\" data-testid=\"input-body\" name=\"body\" required=\"\" value=\"first task!\" />\n </div>\n <input class=\"btn btn-primary\" type=\"submit\" value=\"submit\" />\n </form>\n </div>\n </div>\n</div>\n```\n\nAfter renaming, the previous HTML returns, but with a new name.\n\nAfter clicking \"remove\":\n\n```html\n<div class=\"mb-3\">\n <button type=\"button\" data-testid=\"item-add\" class=\"btn btn-secondary\">add</button>\n</div>\n<div>\n <span class=\"mr-3\">changed name!</span>\n <button type=\"button\" class=\"border-0 btn btn-link mr-3 text-decoration-none\" data-testid=\"item-rename\">rename</button>\n <button type=\"button\" class=\"border-0 btn btn-link text-decoration-none\" data-testid=\"item-remove\">remove</button>\n</div>\n<div class=\"modal-dialog\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <div class=\"modal-title h4\">Remove</div>\n <button type=\"button\" class=\"btn-close\" aria-label=\"Close\"></button>\n </div>\n <div class=\"modal-body\">\n <form>\n <div class=\"form-group\">\n <input class=\"btn btn-danger\" type=\"submit\" value=\"remove\" />\n </div>\n </form>\n </div>\n </div>\n</div>\n```\n\nNotebook entry disappears after removing.\n\n## modals/Add.jsx\n\nImplement a modal window for adding a task. Make sure to cast focus on the input field when the window appears. This is important for usability.\n\n## modals/Rename.jsx\n\nImplement a modal window for renaming a task. Make sure to cast focus on the input field and select the text in it when the window appears. This is important for usability.\n\n## modals/Remove.jsx\n\nImplement a modal window for removing a task.\n\n### Tips\n\n* Docs for built-in hooks: [useState](https://reactjs.org/docs/hooks-state.html), [useEffect](https://reactjs.org/docs/hooks-effect.html), [useRef](https://reactjs.org/docs/hooks-reference.html#useref)\n* Docs for third-party hooks: [useImmer](https://github.com/immerjs/use-immer), [useFormik](https://formik.org/docs/api/useFormik)\n* [React Bootstrap](https://react-bootstrap.github.io/) docs\n* `useImmer()` is used for point-by-point updates in a mutable style, while retaining the advantage of immutable data structures. It is especially suited for making changes to complex data structures, for example, when you need to find an object in a list and change its property. `useState()` is suitable for managing a simple state.\n* Layout may vary\n","has_solution":true,"entity_name":"Modal windows"},"course":{"start_lesson":{"exercise":null,"units":[{"id":7890,"name":"theory","url":"/courses/js-react-hooks/lessons/intro/theory_unit"}],"links":[{"id":424305,"name":"Plugin eslint-plugin-react-hooks","url":"https://www.npmjs.com/package/eslint-plugin-react-hooks#installation"}],"ordered_units":[{"id":7890,"name":"theory","url":"/courses/js-react-hooks/lessons/intro/theory_unit"}],"id":3539,"slug":"intro","state":"approved","name":"Introduction","course_order":100,"goal":"Learning about the course and set up an environment","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"\n\nHooks are a mechanism in React that allows you to work without classes. It doesn't add anything new, but it simplifies code reuse to solve frequent problems.\n\nCurrently, this is the main way to write React applications. But hooks don't replace classes entirely. Moreover, the React team doesn't plan to remove support for classes. And you can do something without classes. An example of how the `useState` hook works for storing the state:\n\n```jsx\n// useState – built-in React hook\n// To be discussed in more detail in the next lesson\nimport React, { useState } from 'react';\n\nconst Example = () => {\n // It is the example of a hook for working with the state\n const [count, setCount] = useState(0);\n\n return (\n <div>\n <p>You clicked {count} time(s)</p>\n <button onClick={() => setCount(count + 1)}>\n Click me\n </button>\n </div>\n );\n};\n```\n\n<!---<p class=\"codepen\" data-height=\"300\" data-default-tab=\"js,result\" data-slug-hash=\"WNZvQqW\" data-user=\"hexlet\" style=\"height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\">\n <span>See the Pen <a href=\"https://codepen.io/hexlet/pen/WNZvQqW\">\n js_react_hooks_use_effect-1</a> by Hexlet (<a href=\"https://codepen.io/hexlet\">@hexlet</a>)\n on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://cpwebassets.codepen.io/assets/embed/ei.js\"></script>--->\n\nHooks are functions with names usually beginning with `use` so they are easy to distinguish. React has about ten hooks built in, only a few of which programmers use regularly. The main ones repeat the functionality of class components, such as working with state, side effects (lifecycle), context, and direct access to the Dom. We'll look at them throughout the course. You can find information on the remaining hooks in the official documentation.\n\nIn addition to the built-in ones, you can find hundreds, if not thousands, of ready-made hooks for all purposes on the web. For example, the popular [react-use](https://github.com/streamich/react-use) has more than 115 hooks. Now, development in React has turned into the search and use of suitable hooks. It is good because you can focus on your tasks and worry less about inventing bicycles.\n"},"id":337,"slug":"js-react-hooks","challenges_count":4,"name":"JS: React Hooks","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"React Hooks is a mechanism that allows building applications without classes, only on functional components. Thanks to hooks, the code becomes smaller, and the level of code reuse becomes higher.","kind":"advanced","updated_at":"2026-01-20T11:46:21.369Z","language":"javascript","duration_cache":19740,"skills":["Use built-in hooks","Create an application consisting of functional components","Implement ready-made hooks for solving typical tasks"],"keywords":[],"lessons_count":5,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NzUyMCwicHVyIjoiYmxvYl9pZCJ9fQ==--f0a2dddfa33850502cb3a06e6fa6b2cf1f8a077d/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJwbmciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--6067466c2912ca31a17eddee04b8cf2a38c6ad17/image.png"},"id":673,"slug":"js_react_modals_exercise","percent_of_success":"-"},{"exercise":{"id":2390,"slug":"js_react_auth_exercise","name":"Authorization","state":"active","kind":"challenge","language":"javascript","locale":"en","has_web_view":true,"has_test_view":false,"reviewable":true,"readme":"В этом испытании вам предстоит реализовать авторизацию в настоящем SPA (single-page application). Идея состоит в том, что при получении валидной пары логин-пароль сервер возвращает токен, который сохраняется в local storage и отправляется на сервер с каждым клиентским запросом. Приложение состоит из главной, публичной и приватной страниц, а также страницы с формой входа. Часть кода уже написана, внимательно изучите файлы приложения. Выполнение испытания потребует изучения новых хуков и библиотек. Рекомендуем проходить это испытание после выполнения [предыдущего](https://ru.hexlet.io/challenges/js_react_modals_exercise).\n\n## components/LoginPage.jsx\n\nРеализуйте компонент с формой авторизации пользователя. Форма содержит поля `username` и `password`. В случае ошибки аутентификации в форме показывается сообщение `the username or password is incorrect`. При успешной проверке полученный с сервера токен необходимо сохранить и сделать редирект на ту страницу, с которой пользователь попал в форму логина. Если пользователь зашёл по прямой ссылке, его следует перенаправить на главную страницу.\n\nПример формы:\n\n```html\n<form>\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"username\">Username</label>\n <input placeholder=\"username\" name=\"username\" autocomplete=\"username\" required id=\"username\" class=\"form-control\">\n </div>\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"password\">Password</label>\n <input placeholder=\"password\" name=\"password\" autocomplete=\"current-password\" required id=\"password\" class=\"form-control\" type=\"password\">\n <div class=\"invalid-feedback\">the username or password is incorrect</div>\n </div>\n <button type=\"submit\" class=\"btn btn-outline-primary\">Submit</button>\n</form>\n```\n\n## components/PrivatePage.jsx\n\nРеализуйте компонент, который запрашивает данные с сервера и выводит их. Для получения данных необходимо к запросу добавить заголовок `Authorization`, содержащий токен. После проверки сервер вернёт строку, которую нужно вывести на странице. Роутинг настроен так, что на страницу `/private` можно попасть только после успешной авторизации.\n\n### Tips\n\n* Для проверки авторизации можно использовать слово `user` в качестве логина и пароля\n* Документация на встроенные хуки: [useState](https://ru.reactjs.org/docs/hooks-state.html), [useEffect](https://ru.reactjs.org/docs/hooks-effect.html), [useRef](https://ru.reactjs.org/docs/hooks-reference.html#useref), [useContext](https://ru.reactjs.org/docs/hooks-reference.html#usecontext)\n* Документация на сторонние хуки: [useImmer](https://github.com/immerjs/use-immer), [useFormik](https://formik.org/docs/api/useFormik)\n* Документация на библиотеки: [React Bootstrap](https://react-bootstrap.github.io/), [react-router-dom](https://reactrouter.com/docs/en/v6)\n","prepared_readme":"В этом испытании вам предстоит реализовать авторизацию в настоящем SPA (single-page application). Идея состоит в том, что при получении валидной пары логин-пароль сервер возвращает токен, который сохраняется в local storage и отправляется на сервер с каждым клиентским запросом. Приложение состоит из главной, публичной и приватной страниц, а также страницы с формой входа. Часть кода уже написана, внимательно изучите файлы приложения. Выполнение испытания потребует изучения новых хуков и библиотек. Рекомендуем проходить это испытание после выполнения [предыдущего](https://ru.hexlet.io/challenges/js_react_modals_exercise).\n\n## components/LoginPage.jsx\n\nРеализуйте компонент с формой авторизации пользователя. Форма содержит поля `username` и `password`. В случае ошибки аутентификации в форме показывается сообщение `the username or password is incorrect`. При успешной проверке полученный с сервера токен необходимо сохранить и сделать редирект на ту страницу, с которой пользователь попал в форму логина. Если пользователь зашёл по прямой ссылке, его следует перенаправить на главную страницу.\n\nПример формы:\n\n```html\n<form>\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"username\">Username</label>\n <input placeholder=\"username\" name=\"username\" autocomplete=\"username\" required id=\"username\" class=\"form-control\">\n </div>\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"password\">Password</label>\n <input placeholder=\"password\" name=\"password\" autocomplete=\"current-password\" required id=\"password\" class=\"form-control\" type=\"password\">\n <div class=\"invalid-feedback\">the username or password is incorrect</div>\n </div>\n <button type=\"submit\" class=\"btn btn-outline-primary\">Submit</button>\n</form>\n```\n\n## components/PrivatePage.jsx\n\nРеализуйте компонент, который запрашивает данные с сервера и выводит их. Для получения данных необходимо к запросу добавить заголовок `Authorization`, содержащий токен. После проверки сервер вернёт строку, которую нужно вывести на странице. Роутинг настроен так, что на страницу `/private` можно попасть только после успешной авторизации.\n\n### Tips\n\n* Для проверки авторизации можно использовать слово `user` в качестве логина и пароля\n* Документация на встроенные хуки: [useState](https://ru.reactjs.org/docs/hooks-state.html), [useEffect](https://ru.reactjs.org/docs/hooks-effect.html), [useRef](https://ru.reactjs.org/docs/hooks-reference.html#useref), [useContext](https://ru.reactjs.org/docs/hooks-reference.html#usecontext)\n* Документация на сторонние хуки: [useImmer](https://github.com/immerjs/use-immer), [useFormik](https://formik.org/docs/api/useFormik)\n* Документация на библиотеки: [React Bootstrap](https://react-bootstrap.github.io/), [react-router-dom](https://reactrouter.com/docs/en/v6)\n","has_solution":true,"entity_name":"Authorization"},"course":{"start_lesson":{"exercise":null,"units":[{"id":7890,"name":"theory","url":"/courses/js-react-hooks/lessons/intro/theory_unit"}],"links":[{"id":424305,"name":"Plugin eslint-plugin-react-hooks","url":"https://www.npmjs.com/package/eslint-plugin-react-hooks#installation"}],"ordered_units":[{"id":7890,"name":"theory","url":"/courses/js-react-hooks/lessons/intro/theory_unit"}],"id":3539,"slug":"intro","state":"approved","name":"Introduction","course_order":100,"goal":"Learning about the course and set up an environment","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"\n\nHooks are a mechanism in React that allows you to work without classes. It doesn't add anything new, but it simplifies code reuse to solve frequent problems.\n\nCurrently, this is the main way to write React applications. But hooks don't replace classes entirely. Moreover, the React team doesn't plan to remove support for classes. And you can do something without classes. An example of how the `useState` hook works for storing the state:\n\n```jsx\n// useState – built-in React hook\n// To be discussed in more detail in the next lesson\nimport React, { useState } from 'react';\n\nconst Example = () => {\n // It is the example of a hook for working with the state\n const [count, setCount] = useState(0);\n\n return (\n <div>\n <p>You clicked {count} time(s)</p>\n <button onClick={() => setCount(count + 1)}>\n Click me\n </button>\n </div>\n );\n};\n```\n\n<!---<p class=\"codepen\" data-height=\"300\" data-default-tab=\"js,result\" data-slug-hash=\"WNZvQqW\" data-user=\"hexlet\" style=\"height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\">\n <span>See the Pen <a href=\"https://codepen.io/hexlet/pen/WNZvQqW\">\n js_react_hooks_use_effect-1</a> by Hexlet (<a href=\"https://codepen.io/hexlet\">@hexlet</a>)\n on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async src=\"https://cpwebassets.codepen.io/assets/embed/ei.js\"></script>--->\n\nHooks are functions with names usually beginning with `use` so they are easy to distinguish. React has about ten hooks built in, only a few of which programmers use regularly. The main ones repeat the functionality of class components, such as working with state, side effects (lifecycle), context, and direct access to the Dom. We'll look at them throughout the course. You can find information on the remaining hooks in the official documentation.\n\nIn addition to the built-in ones, you can find hundreds, if not thousands, of ready-made hooks for all purposes on the web. For example, the popular [react-use](https://github.com/streamich/react-use) has more than 115 hooks. Now, development in React has turned into the search and use of suitable hooks. It is good because you can focus on your tasks and worry less about inventing bicycles.\n"},"id":337,"slug":"js-react-hooks","challenges_count":4,"name":"JS: React Hooks","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"React Hooks is a mechanism that allows building applications without classes, only on functional components. Thanks to hooks, the code becomes smaller, and the level of code reuse becomes higher.","kind":"advanced","updated_at":"2026-01-20T11:46:21.369Z","language":"javascript","duration_cache":19740,"skills":["Use built-in hooks","Create an application consisting of functional components","Implement ready-made hooks for solving typical tasks"],"keywords":[],"lessons_count":5,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NzUyMCwicHVyIjoiYmxvYl9pZCJ9fQ==--f0a2dddfa33850502cb3a06e6fa6b2cf1f8a077d/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJwbmciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--6067466c2912ca31a17eddee04b8cf2a38c6ad17/image.png"},"id":674,"slug":"js_react_auth_exercise","percent_of_success":"-"}],"recommendedLandings":[{"stack":{"id":15,"slug":"frontend","title":"Frontend Developer","audience":"for_beginners","start_type":"anytime","pricing_model":"purchase","priority":"low","kind":"profession","state":"published","stack_state":"finished","order":1,"duration_in_months":10},"id":22,"slug":"frontend","title":"Frontend Developer","subtitle":"","subtitle_for_lists":"","locale":"en","current":true,"duration_in_months_text":"10 months","stack_slug":"frontend","price_text":"from $49","duration_text":"10 months","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTIzNTMsInB1ciI6ImJsb2JfaWQifX0=--f1948fb0c5a45a6d76671a1a32b8cf6f0b53ee57/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Software%20code%20testing-cuate.png"},{"stack":{"id":137,"slug":"js-react-development","title":"React","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"high","kind":"track","state":"published","stack_state":"finished","order":null,"duration_in_months":2},"id":234,"slug":"js-react-development","title":"React","subtitle":"Skill in building fast, user-friendly interfaces that boosts chances of landing exciting roles at top tech companies","subtitle_for_lists":"","locale":"en","current":true,"duration_in_months_text":"2 months","stack_slug":"js-react-development","price_text":"from $49","duration_text":"2 months","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTIzNTAsInB1ciI6ImJsb2JfaWQifX0=--4c31372fe7c51ddbc0ef0d54fe47eaba88a2b04b/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programmer-rafiki.png"}]},"url":"/courses/js-react-hooks","version":"1656487db0d1dd5f33634fe1070e57e55135cbeb","encryptHistory":false,"clearHistory":false}"><style data-mantine-styles="true">:root, :host{--mantine-font-family: Arial, sans-serif;--mantine-font-family-headings: Arial, sans-serif;--mantine-heading-font-weight: normal;--mantine-radius-default: 0rem;--mantine-primary-color-filled: var(--mantine-color-indigo-filled);--mantine-primary-color-filled-hover: var(--mantine-color-indigo-filled-hover);--mantine-primary-color-light: var(--mantine-color-indigo-light);--mantine-primary-color-light-hover: var(--mantine-color-indigo-light-hover);--mantine-primary-color-light-color: var(--mantine-color-indigo-light-color);--mantine-spacing-xxl: calc(4rem * var(--mantine-scale));--mantine-font-size-xs: 12px;--mantine-font-size-sm: 14px;--mantine-font-size-md: 16px;--mantine-font-size-lg: clamp(16.0000px, calc(15.2727px + 0.2273vw), 18.0000px);--mantine-font-size-xl: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-display-3: clamp(32.0000px, calc(26.1818px + 1.8182vw), 48.0000px);--mantine-font-size-display-2: clamp(36.0000px, calc(25.8182px + 3.1818vw), 64.0000px);--mantine-font-size-display-1: clamp(40.0000px, calc(25.4545px + 4.5455vw), 80.0000px);--mantine-font-size-h1: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-font-size-h2: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-font-size-h3: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-font-size-h4: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-font-size-h5: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-h6: 1rem;--mantine-primary-color-0: var(--mantine-color-indigo-0);--mantine-primary-color-1: var(--mantine-color-indigo-1);--mantine-primary-color-2: var(--mantine-color-indigo-2);--mantine-primary-color-3: var(--mantine-color-indigo-3);--mantine-primary-color-4: var(--mantine-color-indigo-4);--mantine-primary-color-5: var(--mantine-color-indigo-5);--mantine-primary-color-6: var(--mantine-color-indigo-6);--mantine-primary-color-7: var(--mantine-color-indigo-7);--mantine-primary-color-8: var(--mantine-color-indigo-8);--mantine-primary-color-9: var(--mantine-color-indigo-9);--mantine-color-red-0: #ffeaea;--mantine-color-red-1: #fed4d4;--mantine-color-red-2: #f4a7a8;--mantine-color-red-3: #ec7878;--mantine-color-red-4: #e55050;--mantine-color-red-5: #e03131;--mantine-color-red-6: #e02829;--mantine-color-red-7: #c71a1c;--mantine-color-red-8: #b21218;--mantine-color-red-9: #9c0411;--mantine-color-violet-0: #fce9ff;--mantine-color-violet-1: #f1cfff;--mantine-color-violet-2: #e09bff;--mantine-color-violet-3: #d16fff;--mantine-color-violet-4: #be37fe;--mantine-color-violet-5: #b51afe;--mantine-color-violet-6: #b009ff;--mantine-color-violet-7: #9b00e4;--mantine-color-violet-8: #8a00cc;--mantine-color-violet-9: #7800b3;--mantine-color-indigo-0: #edecff;--mantine-color-indigo-1: #d6d5fe;--mantine-color-indigo-2: #aaa9f4;--mantine-color-indigo-3: #7b79eb;--mantine-color-indigo-4: #5451e4;--mantine-color-indigo-5: #3b37e0;--mantine-color-indigo-6: #2d2adf;--mantine-color-indigo-7: #1f1ec7;--mantine-color-indigo-8: #1819b2;--mantine-color-indigo-9: #0c149e;--mantine-color-cyan-0: #dffdff;--mantine-color-cyan-1: #caf5ff;--mantine-color-cyan-2: #99e8ff;--mantine-color-cyan-3: #64daff;--mantine-color-cyan-4: #3ccffe;--mantine-color-cyan-5: #24c8fe;--mantine-color-cyan-6: #00c2ff;--mantine-color-cyan-7: #00ade4;--mantine-color-cyan-8: #009acd;--mantine-color-cyan-9: #0085b5;--mantine-color-green-0: #e9fdec;--mantine-color-green-1: #d7f6dc;--mantine-color-green-2: #b0eab9;--mantine-color-green-3: #86df94;--mantine-color-green-4: #62d574;--mantine-color-green-5: #4ccf5f;--mantine-color-green-6: #3fcc54;--mantine-color-green-7: #2fb344;--mantine-color-green-8: #25a03b;--mantine-color-green-9: #138a2e;--mantine-color-yellow-0: #fff7e2;--mantine-color-yellow-1: #ffeecd;--mantine-color-yellow-2: #ffdc9c;--mantine-color-yellow-3: #ffc966;--mantine-color-yellow-4: #feb93a;--mantine-color-yellow-5: #feae1e;--mantine-color-yellow-6: #ffa90f;--mantine-color-yellow-8: #ca8200;--mantine-color-yellow-9: #af7000;--mantine-h1-font-size: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-h1-font-weight: normal;--mantine-h2-font-size: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-h2-font-weight: normal;--mantine-h3-font-size: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-h3-font-weight: normal;--mantine-h4-font-size: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-h4-font-weight: normal;--mantine-h5-font-size: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-h5-font-weight: normal;--mantine-h6-font-size: 1rem;--mantine-h6-font-weight: normal;}
:root[data-mantine-color-scheme="dark"], :host([data-mantine-color-scheme="dark"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-dark-filled: var(--mantine-color-dark-5);--mantine-color-dark-filled-hover: var(--mantine-color-dark-6);--mantine-color-dark-light: rgba(105, 105, 105, 0.15);--mantine-color-dark-light-hover: rgba(105, 105, 105, 0.2);--mantine-color-dark-light-color: var(--mantine-color-dark-0);--mantine-color-dark-outline: var(--mantine-color-dark-1);--mantine-color-dark-outline-hover: rgba(184, 184, 184, 0.05);--mantine-color-gray-filled: var(--mantine-color-gray-5);--mantine-color-gray-filled-hover: var(--mantine-color-gray-6);--mantine-color-gray-light: rgba(222, 226, 230, 0.15);--mantine-color-gray-light-hover: rgba(222, 226, 230, 0.2);--mantine-color-gray-light-color: var(--mantine-color-gray-0);--mantine-color-gray-outline: var(--mantine-color-gray-1);--mantine-color-gray-outline-hover: rgba(241, 243, 245, 0.05);--mantine-color-red-filled: var(--mantine-color-red-5);--mantine-color-red-filled-hover: var(--mantine-color-red-6);--mantine-color-red-light: rgba(236, 120, 120, 0.15);--mantine-color-red-light-hover: rgba(236, 120, 120, 0.2);--mantine-color-red-light-color: var(--mantine-color-red-0);--mantine-color-red-outline: var(--mantine-color-red-1);--mantine-color-red-outline-hover: rgba(254, 212, 212, 0.05);--mantine-color-pink-filled: var(--mantine-color-pink-5);--mantine-color-pink-filled-hover: var(--mantine-color-pink-6);--mantine-color-pink-light: rgba(250, 162, 193, 0.15);--mantine-color-pink-light-hover: rgba(250, 162, 193, 0.2);--mantine-color-pink-light-color: var(--mantine-color-pink-0);--mantine-color-pink-outline: var(--mantine-color-pink-1);--mantine-color-pink-outline-hover: rgba(255, 222, 235, 0.05);--mantine-color-grape-filled: var(--mantine-color-grape-5);--mantine-color-grape-filled-hover: var(--mantine-color-grape-6);--mantine-color-grape-light: rgba(229, 153, 247, 0.15);--mantine-color-grape-light-hover: rgba(229, 153, 247, 0.2);--mantine-color-grape-light-color: var(--mantine-color-grape-0);--mantine-color-grape-outline: var(--mantine-color-grape-1);--mantine-color-grape-outline-hover: rgba(243, 217, 250, 0.05);--mantine-color-violet-filled: var(--mantine-color-violet-5);--mantine-color-violet-filled-hover: var(--mantine-color-violet-6);--mantine-color-violet-light: rgba(209, 111, 255, 0.15);--mantine-color-violet-light-hover: rgba(209, 111, 255, 0.2);--mantine-color-violet-light-color: var(--mantine-color-violet-0);--mantine-color-violet-outline: var(--mantine-color-violet-1);--mantine-color-violet-outline-hover: rgba(241, 207, 255, 0.05);--mantine-color-indigo-filled: var(--mantine-color-indigo-5);--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-6);--mantine-color-indigo-light: rgba(123, 121, 235, 0.15);--mantine-color-indigo-light-hover: rgba(123, 121, 235, 0.2);--mantine-color-indigo-light-color: var(--mantine-color-indigo-0);--mantine-color-indigo-outline: var(--mantine-color-indigo-1);--mantine-color-indigo-outline-hover: rgba(214, 213, 254, 0.05);--mantine-color-blue-filled: var(--mantine-color-blue-5);--mantine-color-blue-filled-hover: var(--mantine-color-blue-6);--mantine-color-blue-light: rgba(116, 192, 252, 0.15);--mantine-color-blue-light-hover: rgba(116, 192, 252, 0.2);--mantine-color-blue-light-color: var(--mantine-color-blue-0);--mantine-color-blue-outline: var(--mantine-color-blue-1);--mantine-color-blue-outline-hover: rgba(208, 235, 255, 0.05);--mantine-color-cyan-filled: var(--mantine-color-cyan-5);--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-6);--mantine-color-cyan-light: rgba(100, 218, 255, 0.15);--mantine-color-cyan-light-hover: rgba(100, 218, 255, 0.2);--mantine-color-cyan-light-color: var(--mantine-color-cyan-0);--mantine-color-cyan-outline: var(--mantine-color-cyan-1);--mantine-color-cyan-outline-hover: rgba(202, 245, 255, 0.05);--mantine-color-teal-filled: var(--mantine-color-teal-5);--mantine-color-teal-filled-hover: var(--mantine-color-teal-6);--mantine-color-teal-light: rgba(99, 230, 190, 0.15);--mantine-color-teal-light-hover: rgba(99, 230, 190, 0.2);--mantine-color-teal-light-color: var(--mantine-color-teal-0);--mantine-color-teal-outline: var(--mantine-color-teal-1);--mantine-color-teal-outline-hover: rgba(195, 250, 232, 0.05);--mantine-color-green-filled: var(--mantine-color-green-5);--mantine-color-green-filled-hover: var(--mantine-color-green-6);--mantine-color-green-light: rgba(134, 223, 148, 0.15);--mantine-color-green-light-hover: rgba(134, 223, 148, 0.2);--mantine-color-green-light-color: var(--mantine-color-green-0);--mantine-color-green-outline: var(--mantine-color-green-1);--mantine-color-green-outline-hover: rgba(215, 246, 220, 0.05);--mantine-color-lime-filled: var(--mantine-color-lime-5);--mantine-color-lime-filled-hover: var(--mantine-color-lime-6);--mantine-color-lime-light: rgba(192, 235, 117, 0.15);--mantine-color-lime-light-hover: rgba(192, 235, 117, 0.2);--mantine-color-lime-light-color: var(--mantine-color-lime-0);--mantine-color-lime-outline: var(--mantine-color-lime-1);--mantine-color-lime-outline-hover: rgba(233, 250, 200, 0.05);--mantine-color-yellow-filled: var(--mantine-color-yellow-5);--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-6);--mantine-color-yellow-light: rgba(255, 201, 102, 0.15);--mantine-color-yellow-light-hover: rgba(255, 201, 102, 0.2);--mantine-color-yellow-light-color: var(--mantine-color-yellow-0);--mantine-color-yellow-outline: var(--mantine-color-yellow-1);--mantine-color-yellow-outline-hover: rgba(255, 238, 205, 0.05);--mantine-color-orange-filled: var(--mantine-color-orange-5);--mantine-color-orange-filled-hover: var(--mantine-color-orange-6);--mantine-color-orange-light: rgba(255, 192, 120, 0.15);--mantine-color-orange-light-hover: rgba(255, 192, 120, 0.2);--mantine-color-orange-light-color: var(--mantine-color-orange-0);--mantine-color-orange-outline: var(--mantine-color-orange-1);--mantine-color-orange-outline-hover: rgba(255, 232, 204, 0.05);--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-9) 0%, var(--mantine-color-cyan-7) 100%);--app-color-surface: #2e2e2e;}
:root[data-mantine-color-scheme="light"], :host([data-mantine-color-scheme="light"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-red-light: rgba(224, 40, 41, 0.1);--mantine-color-red-light-hover: rgba(224, 40, 41, 0.12);--mantine-color-red-outline-hover: rgba(224, 40, 41, 0.05);--mantine-color-violet-light: rgba(176, 9, 255, 0.1);--mantine-color-violet-light-hover: rgba(176, 9, 255, 0.12);--mantine-color-violet-outline-hover: rgba(176, 9, 255, 0.05);--mantine-color-indigo-light: rgba(45, 42, 223, 0.1);--mantine-color-indigo-light-hover: rgba(45, 42, 223, 0.12);--mantine-color-indigo-outline-hover: rgba(45, 42, 223, 0.05);--mantine-color-cyan-light: rgba(0, 194, 255, 0.1);--mantine-color-cyan-light-hover: rgba(0, 194, 255, 0.12);--mantine-color-cyan-outline-hover: rgba(0, 194, 255, 0.05);--mantine-color-green-light: rgba(63, 204, 84, 0.1);--mantine-color-green-light-hover: rgba(63, 204, 84, 0.12);--mantine-color-green-outline-hover: rgba(63, 204, 84, 0.05);--mantine-color-yellow-light: rgba(255, 169, 15, 0.1);--mantine-color-yellow-light-hover: rgba(255, 169, 15, 0.12);--mantine-color-yellow-outline-hover: rgba(255, 169, 15, 0.05);--app-color-surface: #f1f3f5;--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-5) 100%);}</style><style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style><div style="--container-size:var(--container-size-lg);margin-top:var(--mantine-spacing-xl);height:100%" class="m_7485cace mantine-Container-root" data-size="lg" data-strategy="block"><style data-mantine-styles="inline">.__m__-_R_eub_{margin-bottom:var(--mantine-spacing-xs);}@media(min-width: 36em){.__m__-_R_eub_{margin-bottom:var(--mantine-spacing-xs);}}</style><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root __m__-_R_eub_"><style data-mantine-styles="inline">.__m__-_R_deub_{width:100%;}@media(min-width: 62em){.__m__-_R_deub_{width:66%;}}</style><div class="__m__-_R_deub_"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><h1 style="--title-fw:var(--mantine-h1-font-weight);--title-lh:var(--mantine-h1-line-height);--title-fz:var(--mantine-h1-font-size)" class="m_8a5d1357 mantine-Title-root" data-order="1">Course “JS: React Hooks”</h1></div></div></div><style data-mantine-styles="inline">.__m__-_R_1iub_{width:100%;}@media(min-width: 62em){.__m__-_R_1iub_{width:66%;}}</style><div style="margin-bottom:var(--mantine-spacing-xl)" class="__m__-_R_1iub_"><div style="margin-bottom:var(--mantine-spacing-lg)" class=""></div><div style="margin-top:var(--mantine-spacing-lg)" class="mantine-hidden-from-md"><div style="--stack-gap:var(--mantine-spacing-xs);--stack-align:stretch;--stack-justify:flex-start" class="m_6d731127 mantine-Stack-root"><a style="--button-height:var(--button-height-md);--button-padding-x:var(--button-padding-x-md);--button-fz:var(--mantine-font-size-md);--button-color:var(--mantine-color-white);text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto mantine-active m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-size="md" data-underline="hover" href="https://hexlet.io/subscription/new"><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">Subscribe</span></span></a><p style="color:var(--mantine-color-dimmed);font-size:var(--mantine-font-size-sm);text-align:center" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Access this and all courses with a subscription</p></div></div></div><style data-mantine-styles="inline">.__m__-_R_2iub_{--grid-gutter:var(--mantine-spacing-md);}</style><div class="m_410352e9 mantine-Grid-root __m__-_R_2iub_"><div class="m_dee7bd2f mantine-Grid-inner"><style data-mantine-styles="inline">.__m__-_R_dmiub_{--col-flex-grow:auto;--col-flex-basis:100%;--col-max-width:100%;}@media(min-width: 62em){.__m__-_R_dmiub_{--col-flex-grow:auto;--col-flex-basis:66.66666666666667%;--col-max-width:66.66666666666667%;}}</style><div class="m_96bdd299 mantine-Grid-col __m__-_R_dmiub_"><div style="margin-bottom:var(--mantine-spacing-xl);padding-inline:var(--mantine-spacing-xl);padding-block:var(--mantine-spacing-lg)" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><p style="margin-bottom:var(--mantine-spacing-md);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">What's included</p><style data-mantine-styles="inline">.__m__-_R_ajddmiub_{--sg-spacing-x:var(--mantine-spacing-xs);--sg-spacing-y:var(--mantine-spacing-xs);--sg-cols:1;}@media(min-width: 48em){.__m__-_R_ajddmiub_{--sg-cols:2;}}</style><div class="m_2415a157 mantine-SimpleGrid-root __m__-_R_ajddmiub_"><div style="align-items:center" class="m_8bffd616 mantine-Flex-root __m__-_R_1mqjddmiub_"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:var(--mantine-spacing-xs);color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-check "><path d="M5 12l5 5l10 -10"></path></svg></div>5 lessons (video and/or text)</div><div style="align-items:center" class="m_8bffd616 mantine-Flex-root __m__-_R_2mqjddmiub_"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:var(--mantine-spacing-xs);color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-check "><path d="M5 12l5 5l10 -10"></path></svg></div>4 exercises in the simulator</div><div style="align-items:center" class="m_8bffd616 mantine-Flex-root __m__-_R_3mqjddmiub_"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:var(--mantine-spacing-xs);color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-check "><path d="M5 12l5 5l10 -10"></path></svg></div>14 verification tests</div><div style="align-items:center" class="m_8bffd616 mantine-Flex-root __m__-_R_4mqjddmiub_"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:var(--mantine-spacing-xs);color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-check "><path d="M5 12l5 5l10 -10"></path></svg></div>Self-study tasks</div><div style="align-items:center" class="m_8bffd616 mantine-Flex-root __m__-_R_5mqjddmiub_"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:var(--mantine-spacing-xs);color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-check "><path d="M5 12l5 5l10 -10"></path></svg></div>Extra materials</div><div style="align-items:center" class="m_8bffd616 mantine-Flex-root __m__-_R_6mqjddmiub_"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:var(--mantine-spacing-xs);color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-plus "><path d="M12 5l0 14"></path><path d="M5 12l14 0"></path></svg></div>5 extended materials</div></div></div><div style="margin-bottom:var(--mantine-spacing-xl)" class=""><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md)" class="m_8a5d1357 mantine-Title-root" data-order="2">Description</h2><div class="m_d08caa0 mantine-Typography-root"><p>React Hooks is a mechanism that allows building applications without classes, only on functional components. Thanks to hooks, the code becomes smaller, and the level of code reuse becomes higher.</p></div></div><div style="margin-bottom:var(--mantine-spacing-xl)" class=""><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md)" class="m_8a5d1357 mantine-Title-root" data-order="2">You will learn</h2><ul class="m_abbac491 mantine-List-root" data-type="none"><li style="margin-bottom:var(--mantine-spacing-xs);line-height:var(--mantine-line-height-sm)" class="m_abb6bec2 mantine-List-item" data-with-icon="true" data-centered="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-plus "><path d="M12 5l0 14"></path><path d="M5 12l14 0"></path></svg></div></span><span class="mantine-List-itemLabel">Use built-in hooks</span></div></li><li style="margin-bottom:var(--mantine-spacing-xs);line-height:var(--mantine-line-height-sm)" class="m_abb6bec2 mantine-List-item" data-with-icon="true" data-centered="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-plus "><path d="M12 5l0 14"></path><path d="M5 12l14 0"></path></svg></div></span><span class="mantine-List-itemLabel">Create an application consisting of functional components</span></div></li><li style="margin-bottom:var(--mantine-spacing-xs);line-height:var(--mantine-line-height-sm)" class="m_abb6bec2 mantine-List-item" data-with-icon="true" data-centered="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-plus "><path d="M12 5l0 14"></path><path d="M5 12l14 0"></path></svg></div></span><span class="mantine-List-itemLabel">Implement ready-made hooks for solving typical tasks</span></div></li></ul></div><div style="margin-bottom:var(--mantine-spacing-xl)" class=""><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md)" class="m_8a5d1357 mantine-Title-root" data-order="2">Syllabus</h2><table style="--table-vertical-spacing:calc(0.4375rem * var(--mantine-scale))" class="m_b23fa0ef mantine-Table-table"><tbody class="m_b2404537 mantine-Table-tbody"><tr class="m_4e7aa4fd mantine-Table-tr" data-with-row-border="true"><td class="m_4e7aa4ef mantine-Table-td"><p style="font-size:var(--mantine-font-size-h4)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">1</p></td><td style="padding-block:var(--mantine-spacing-lg)" class="m_4e7aa4ef mantine-Table-td"><a style="color:inherit;font-size:var(--mantine-font-size-h5)" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/js-react-hooks/lessons/intro/theory_unit">Introduction</a><p style="color:var(--mantine-color-dimmed)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Learning about the course and set up an environment</p></td></tr><tr class="m_4e7aa4fd mantine-Table-tr" data-with-row-border="true"><td class="m_4e7aa4ef mantine-Table-td"><p style="font-size:var(--mantine-font-size-h4)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">2</p></td><td style="padding-block:var(--mantine-spacing-lg)" class="m_4e7aa4ef mantine-Table-td"><a style="color:inherit;font-size:var(--mantine-font-size-h5)" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/js-react-hooks/lessons/use-state/theory_unit">useState Hook</a><p style="color:var(--mantine-color-dimmed)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Exploring how hooks work and learn the most basic one, which is responsible for managing state</p></td></tr><tr class="m_4e7aa4fd mantine-Table-tr" data-with-row-border="true"><td class="m_4e7aa4ef mantine-Table-td"><p style="font-size:var(--mantine-font-size-h4)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">3</p></td><td style="padding-block:var(--mantine-spacing-lg)" class="m_4e7aa4ef mantine-Table-td"><a style="color:inherit;font-size:var(--mantine-font-size-h5)" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/js-react-hooks/lessons/use-effect/theory_unit">useEffect Hook</a><p style="color:var(--mantine-color-dimmed)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Learning how to properly isolate side effects with hooks</p></td></tr><tr class="m_4e7aa4fd mantine-Table-tr" data-with-row-border="true"><td class="m_4e7aa4ef mantine-Table-td"><p style="font-size:var(--mantine-font-size-h4)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">4</p></td><td style="padding-block:var(--mantine-spacing-lg)" class="m_4e7aa4ef mantine-Table-td"><a style="color:inherit;font-size:var(--mantine-font-size-h5)" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/js-react-hooks/lessons/use-context/theory_unit">useContext Hook</a><p style="color:var(--mantine-color-dimmed)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Learning to work with context through hooks</p></td></tr><tr class="m_4e7aa4fd mantine-Table-tr" data-with-row-border="true"><td class="m_4e7aa4ef mantine-Table-td"><p style="font-size:var(--mantine-font-size-h4)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">5</p></td><td style="padding-block:var(--mantine-spacing-lg)" class="m_4e7aa4ef mantine-Table-td"><a style="color:inherit;font-size:var(--mantine-font-size-h5)" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/js-react-hooks/lessons/use-ref/theory_unit">useRef Hook</a><p style="color:var(--mantine-color-dimmed)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Learning how to access DOM elements with hooks</p></td></tr></tbody></table></div><div style="margin-bottom:var(--mantine-spacing-xl)" class=""><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:flex-start;--group-wrap:wrap;margin-bottom:var(--mantine-spacing-md)" class="m_4081bf90 mantine-Group-root"><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size)" class="m_8a5d1357 mantine-Title-root" data-order="2">Challenges</h2><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:transparent;--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:var(--mantine-color-dimmed)" class="mantine-focus-auto mantine-active m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="transparent" data-size="sm" type="button" aria-haspopup="dialog" aria-expanded="false" id="mantine-_R_amtddmiub_-target"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-info-square-rounded "><path d="M12 9h.01"></path><path d="M11 12h1v4h1"></path><path d="M12 3c7.2 0 9 1.8 9 9c0 7.2 -1.8 9 -9 9c-7.2 0 -9 -1.8 -9 -9c0 -7.2 1.8 -9 9 -9"></path></svg></span></button></div><table style="--table-vertical-spacing:calc(0.4375rem * var(--mantine-scale))" class="m_b23fa0ef mantine-Table-table"><tbody class="m_b2404537 mantine-Table-tbody"><tr class="m_4e7aa4fd mantine-Table-tr" data-with-row-border="true"><td class="m_4e7aa4ef mantine-Table-td"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">1</p></td><td class="m_4e7aa4ef mantine-Table-td"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Don't touch me</p></td></tr><tr class="m_4e7aa4fd mantine-Table-tr" data-with-row-border="true"><td class="m_4e7aa4ef mantine-Table-td"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">2</p></td><td class="m_4e7aa4ef mantine-Table-td"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Table</p></td></tr><tr class="m_4e7aa4fd mantine-Table-tr" data-with-row-border="true"><td class="m_4e7aa4ef mantine-Table-td"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">3</p></td><td class="m_4e7aa4ef mantine-Table-td"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Modal windows</p></td></tr><tr class="m_4e7aa4fd mantine-Table-tr" data-with-row-border="true"><td class="m_4e7aa4ef mantine-Table-td"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">4</p></td><td class="m_4e7aa4ef mantine-Table-td"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Authorization</p></td></tr></tbody></table></div><div class=""><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md)" class="m_8a5d1357 mantine-Title-root" data-order="2">Recommended programs</h2><style data-mantine-styles="inline">.__m__-_R_avddmiub_{--carousel-slide-gap:var(--mantine-spacing-xs);--carousel-slide-size:70%;}@media(min-width: 36em){.__m__-_R_avddmiub_{--carousel-slide-gap:var(--mantine-spacing-xl);--carousel-slide-size:50%;}}</style><div style="--carousel-control-size:calc(2.5rem * var(--mantine-scale));--carousel-controls-offset:var(--mantine-spacing-sm);margin-bottom:var(--mantine-spacing-lg);padding-block:var(--mantine-spacing-sm);background:var(--app-color-surface)" class="m_17884d0f mantine-Carousel-root responsiveClassName" data-orientation="horizontal" data-include-gap-in-size="true"><div class="m_39bc3463 mantine-Carousel-controls" data-orientation="horizontal"><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="previous" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="next" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(-90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div><div class="m_a2dae653 mantine-Carousel-viewport" data-type="media"><div class="m_fcd81474 mantine-Carousel-container __m__-_R_avddmiub_" data-orientation="horizontal"><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/frontend?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">10 months</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">For beginners</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Frontend Developer</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root"></p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTIzNTMsInB1ciI6ImJsb2JfaWQifX0=--f1948fb0c5a45a6d76671a1a32b8cf6f0b53ee57/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Software%20code%20testing-cuate.png" alt="Frontend Developer" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">from $49</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Explore →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/js-react-development?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">2 months</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">For advanced</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">React</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root"></p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTIzNTAsInB1ciI6ImJsb2JfaWQifX0=--4c31372fe7c51ddbc0ef0d54fe47eaba88a2b04b/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programmer-rafiki.png" alt="React" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">from $49</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Explore →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md);font-size:var(--mantine-font-size-h3)" class="m_8a5d1357 mantine-Title-root" data-order="2" data-responsive="true">Catalog</h2><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">A complete list of available courses by direction</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="/vite/assets/development-BVihs_d5.png" alt="Orientation"/></div></div></div></a></div></div></div></div></div></div></div><style data-mantine-styles="inline">.__m__-_R_lmiub_{--col-flex-grow:auto;--col-flex-basis:100%;--col-max-width:100%;}@media(min-width: 62em){.__m__-_R_lmiub_{--col-flex-grow:auto;--col-flex-basis:33.333333333333336%;--col-max-width:33.333333333333336%;}}</style><div class="m_96bdd299 mantine-Grid-col __m__-_R_lmiub_"><div style="--paper-shadow:var(--mantine-shadow-sm);margin-top:calc(-10.625rem * var(--mantine-scale));padding:0rem;position:sticky;top:calc(3.125rem * var(--mantine-scale))" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root mantine-visible-from-md"><div class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root"><div style="margin-bottom:var(--mantine-spacing-md)" class="m_599a2148 mantine-Card-section" data-first-section="true"><img class="m_9e117634 mantine-Image-root" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NzUyMCwicHVyIjoiYmxvYl9pZCJ9fQ==--f0a2dddfa33850502cb3a06e6fa6b2cf1f8a077d/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJwbmciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--6067466c2912ca31a17eddee04b8cf2a38c6ad17/image.png" alt="Course Cover"/></div><ul style="margin-bottom:var(--mantine-spacing-md)" class="m_abbac491 mantine-List-root"><li style="line-height:var(--mantine-line-height-xl)" class="m_abb6bec2 mantine-List-item" data-with-icon="true" data-centered="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-device-desktop-code "><path d="M12.5 16h-8.5a1 1 0 0 1 -1 -1v-10a1 1 0 0 1 1 -1h16a1 1 0 0 1 1 1v8"></path><path d="M7 20h4"></path><path d="M9 16v4"></path><path d="M20 21l2 -2l-2 -2"></path><path d="M17 17l-2 2l2 2"></path></svg></span><span class="mantine-List-itemLabel">Run code right in the browser</span></div></li><li style="line-height:var(--mantine-line-height-xl)" class="m_abb6bec2 mantine-List-item" data-with-icon="true" data-centered="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-infinity "><path d="M9.828 9.172a4 4 0 1 0 0 5.656a10 10 0 0 0 2.172 -2.828a10 10 0 0 1 2.172 -2.828a4 4 0 1 1 0 5.656a10 10 0 0 1 -2.172 -2.828a10 10 0 0 0 -2.172 -2.828"></path></svg></span><span class="mantine-List-itemLabel">Lifetime access</span></div></li><li style="line-height:var(--mantine-line-height-xl)" class="m_abb6bec2 mantine-List-item" data-with-icon="true" data-centered="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-clock "><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"></path><path d="M12 7v5l3 3"></path></svg></span><span class="mantine-List-itemLabel">Learn at your own pace</span></div></li></ul><div style="--stack-gap:var(--mantine-spacing-xs);--stack-align:stretch;--stack-justify:flex-start" class="m_6d731127 mantine-Stack-root"><a style="--button-height:var(--button-height-md);--button-padding-x:var(--button-padding-x-md);--button-fz:var(--mantine-font-size-md);--button-color:var(--mantine-color-white);text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto mantine-active m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-size="md" data-underline="hover" href="https://hexlet.io/subscription/new"><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">Subscribe</span></span></a><p style="color:var(--mantine-color-dimmed);font-size:var(--mantine-font-size-sm);text-align:center" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Access this and all courses with a subscription</p></div></div></div></div></div></div></div></div>
</main>
<footer class="bg-dark fw-light text-light px-3 py-5">
<div class="row small">
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 mb-3">About Hexlet</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/about">About us</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://help.hexlet.io/category/4316" data-target="_blank" role="button">Help</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" target="_blank" rel="noopener noreferrer" href="/map">Site Map</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 fw-normal mb-3">Learn</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_backend-development">Backend
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_devops">DevOps
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_frontend-development">Frontend
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_python">Python
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_testing">Testing
</a></li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5"><span class="translation_missing" title="translation missing: en.layouts.footer_content.popular_courses_for_beginners">Popular Courses For Beginners</span></div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/frontend">Frontend Developer</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5"><span class="translation_missing" title="translation missing: en.layouts.footer_content.popular_courses_for_advanced">Popular Courses For Advanced</span></div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/web-development-free">Fundamentals of Web Development</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-react-development">React</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/css-animation">CSS Animation</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/http-api">HTTP API</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/layout-designer-positioning">Position CSS</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/cli-basics">Command line basics</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/git-basics-free">Git fundamentals</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 col-sm-4 col-md-2">
<div class="fs-4">
<ul class="list-unstyled d-flex">
<li class="me-3">
<a aria-label="Facebook" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.facebook.com/hexlethq"><span class="bi bi-facebook"></span>
</a></li>
<li class="me-3">
<a aria-label="Instagram" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.instagram.com/hello_hexlet/"><span class="bi bi-instagram"></span>
</a></li>
<li>
<a aria-label="Twitter" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://twitter.com/Hexlet_IO"><span class="bi bi-twitter-x"></span>
</a></li>
</ul>
</div>
<div class="mb-2 d-flex flex-column">
<a class="link-light text-decoration-none" rel="nofollow" href="mailto:support@hexlet.io">support@hexlet.io</a>
<a class="link-light text-decoration-none py-2" target="_blank" href="https://t.me/hexlet_help_bot">t.me/hexlet_help_bot</a>
</div>
<ul class="list-unstyled d-flex">
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 opacity-100 external-link" rel="nofollow" data-href="https://hexlet.io/locale/switch?new_locale=en" data-target="_self" role="button"><span class="my-auto">EN</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://ru.hexlet.io/locale/switch?new_locale=ru" data-target="_self" role="button"><span class="my-auto">RU</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://kz.hexlet.io/locale/switch?new_locale=kz" data-target="_self" role="button"><span class="my-auto">KZ</span>
</span></li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled fs-4">
<li class="mb-3">
<a class="link-light text-decoration-none" href="tel:%2B7%20717%20272%2076%2070">+7 717 272 76 70</a>
<span class="d-block opacity-50 small">free call</span>
</li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled small">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/legal">Legal</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/offer"><span class="translation_missing" title="translation missing: en.layouts.footer_content.offer">Offer</span></a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/contacts"><span class="translation_missing" title="translation missing: en.layouts.footer_content.contacts">Contacts</span></a>
</li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-4 small">
<div class="mb-2">
<div>TOO "Hexlet"</div>
<div>The Republic of Kazakhstan, Almaty</div>
<div>Auezova St., 14A</div>
<div>BIN 230340043714
</div>
</div>
</div>
</div>
</footer>
<div id="root-assistant-offcanvas"></div>
<script src="/vite/assets/assistant-CIOaBlj-.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-0bhwJkNI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-V3hfk_CP.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/MarkdownBlock-DejNWqwz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-B-jV56Ol.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-DOJkeu70.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/shiki-DZwEN4Zo.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-ClTF9s_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-mvvEXZQ8.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-CJocDKTE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-DH3_MBnL.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-Cj65YiRw.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useIsomorphicEffect-Csl7vw8x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-DeAQqnBE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-CN66HKVH.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/classnames-DQgTDFJJ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-Bfba02I7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/debounce-BcxwEZ7X.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/prop-types-DGBR76ns.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-CYyKzrjQ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-SJZekO2j.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-bo78L81P.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-BhqaZ6vG.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-DlXMvSuQ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CFtMU8gd.js" as="script" crossorigin="anonymous">
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/vcd15cbe7772f49c399c6a5babf22c1241717689176015" integrity="sha512-ZpsOmlRQV6y907TI0dKBHq9Md29nnaEIPlkf84rnaERnq6zvWvPUqr2ft8M1aS28oN72PdrCzSjY4U6VaAw1EQ==" data-cf-beacon='{"version":"2024.11.0","token":"d11015b65d11429ea6b4a2ef37dd7e0b","server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>