{"componentChunkName":"component---src-templates-docs-js","path":"/docs/hooks-rules.html","result":{"data":{"markdownRemark":{"html":"<p><em>Хуки</em> — це нововведення в React 16.8. Вони дозволяють вам використовувати стан та інші можливості React без написання класів.</p>\n<p>Хуки — звичайні JavaScript функції, але ви маєте дотримуватися двох правил, використовуючи їх. Ми зробили <a href=\"https://www.npmjs.com/package/eslint-plugin-react-hooks\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">плагін для лінтеру</a>, щоб автоматично дотримуватися цих правил:</p>\n<h3 id=\"only-call-hooks-at-the-top-level\"><a href=\"#only-call-hooks-at-the-top-level\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Використовуйте хуки тільки на вищому рівні </h3>\n<p><strong>Не використовуйте хуки усередині циклів, умовних операторів або вкладених функцій.</strong> Замість цього завжди використовуйте хуки на вищому рівні React-функцій. Дотримуючись цього правила, ви будете певні, що хуки викликаються в однаковій послідовності кожного разу, коли рендериться компонент. Це дозволяє React коректно зберігати стан хуків між численними викликами <code class=\"gatsby-code-text\">useState</code> та <code class=\"gatsby-code-text\">useEffect</code>. (Якщо вам цікаво, то ми пояснимо це більш детально <a href=\"#explanation\">нижче</a>.)</p>\n<h3 id=\"only-call-hooks-from-react-functions\"><a href=\"#only-call-hooks-from-react-functions\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Викликайте хуки лише з React-функцій </h3>\n<p><strong>Не викликайте хуки зі звичайних JavaScript-функцій.</strong> Натомість, ви можете:</p>\n<ul>\n<li>✅ Викликати хуки з функціонального компоненту React.</li>\n<li>✅ Викликати хуки з користувацьких хуків (ми навчимося це робити <a href=\"/docs/hooks-custom.html\">на наступній сторінці</a>).</li>\n</ul>\n<p>Дотримуючись цього правила, ви можете бути певні, що вся логіка компоненту зі станом чітко проглядається в його вихідному коді.</p>\n<h2 id=\"eslint-plugin\"><a href=\"#eslint-plugin\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Плагін для ESLint </h2>\n<p>Ми випустили плагін для ESLint <a href=\"https://www.npmjs.com/package/eslint-plugin-react-hooks\" target=\"_blank\" rel=\"nofollow noopener noreferrer\"><code class=\"gatsby-code-text\">eslint-plugin-react-hooks</code></a>, який примушує дотримуватися цих двох правил. Ви можете додати цей плагін до вашого проекту, якщо ви хочете його спробувати:</p>\n<p>This plugin is included by default in <a href=\"/docs/create-a-new-react-app.html#create-react-app\">Create React App</a>.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"gatsby-code-bash\"><code class=\"gatsby-code-bash\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span> eslint-plugin-react-hooks --save-dev</code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token comment\">// Ваша конфігурація ESLint</span>\n<span class=\"token punctuation\">{</span>\n  <span class=\"token string\">\"plugins\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token comment\">// ...</span>\n    <span class=\"token string\">\"react-hooks\"</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token string\">\"rules\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// ...</span>\n    <span class=\"token string\">\"react-hooks/rules-of-hooks\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"error\"</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// Перевіряє правила хуків</span>\n    <span class=\"token string\">\"react-hooks/exhaustive-deps\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"warn\"</span> <span class=\"token comment\">// Перевіряє ефект залежностей</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong>Ви можете пропустити залишок сторінки та перейти до наступної, яка пояснює як писати <a href=\"/docs/hooks-custom.html\">користувацькі хуки</a>.</strong> На цій сторінці ми продовжимо і надамо пояснення необхідності цих правил.</p>\n<h2 id=\"explanation\"><a href=\"#explanation\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Пояснення </h2>\n<p>Як ми <a href=\"/docs/hooks-state.html#tip-using-multiple-state-variables\">дізналися раніше</a>, в одному компоненті можна багаторазово використовувати хуки стану або ефектів:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token keyword\">function</span> <span class=\"token function\">Form</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// 1. Використовуємо змінну стану name</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>name<span class=\"token punctuation\">,</span> setName<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Ліна'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token comment\">// 2. Використовуємо ефект для збереження стану форми</span>\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span> <span class=\"token function\">persistForm</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    localStorage<span class=\"token punctuation\">.</span><span class=\"token function\">setItem</span><span class=\"token punctuation\">(</span><span class=\"token string\">'formData'</span><span class=\"token punctuation\">,</span> name<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token comment\">// 3. Використовуємо змінну стану state</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>surname<span class=\"token punctuation\">,</span> setSurname<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Костенко'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token comment\">// 4. Використовуємо ефект, щоб оновити заголовок сторінки</span>\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span> <span class=\"token function\">updateTitle</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    document<span class=\"token punctuation\">.</span>title <span class=\"token operator\">=</span> name <span class=\"token operator\">+</span> <span class=\"token string\">' '</span> <span class=\"token operator\">+</span> surname<span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Отже, як React дізнається який стан відповідає певному виклику <code class=\"gatsby-code-text\">useState</code>? Відповідь наступна: <strong>React покладається на послідовність викликів хуків</strong>. Наш приклад працює тому, що послідовність викликів хуків є сталою для кожного рендеру:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token comment\">// ------------</span>\n<span class=\"token comment\">// Перший рендер</span>\n<span class=\"token comment\">// ------------</span>\n<span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Ліна'</span><span class=\"token punctuation\">)</span>           <span class=\"token comment\">// 1. Ініціюємо змінну name зі значенням 'Ліна'</span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>persistForm<span class=\"token punctuation\">)</span>     <span class=\"token comment\">// 2. Додаємо ефект, щоб зберегти данні форми</span>\n<span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Костенко'</span><span class=\"token punctuation\">)</span>        <span class=\"token comment\">// 3. Ініціюємо змінну surname зі значенням 'Костенко'</span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>updateTitle<span class=\"token punctuation\">)</span>     <span class=\"token comment\">// 4. Додаємо ефект, щоб оновити заголовок сторінки</span>\n\n<span class=\"token comment\">// -------------</span>\n<span class=\"token comment\">// Другий рендер</span>\n<span class=\"token comment\">// -------------</span>\n<span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Ліна'</span><span class=\"token punctuation\">)</span>           <span class=\"token comment\">// 1. Зчитуємо змінну стану name (аргумент ігнорується)</span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>persistForm<span class=\"token punctuation\">)</span>     <span class=\"token comment\">// 2. Змінюємо ефект, щоб зберегти данні форми</span>\n<span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Костенко'</span><span class=\"token punctuation\">)</span>        <span class=\"token comment\">// 3. Зчитуємо змінну стану surname (аргумент ігнорується)</span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>updateTitle<span class=\"token punctuation\">)</span>     <span class=\"token comment\">// 4. Змінюємо ефект, щоб оновити заголовок сторінки</span>\n\n<span class=\"token comment\">// ...</span></code></pre></div>\n<p>Доки послідовність викликів хуків залишається сталою між рендерами, React може співвідносити локальний стан між кожним з них. Але, що трапиться, якщо ми розмістимо виклик хуку (наприклад, ефект <code class=\"gatsby-code-text\">persistForm</code>) всередину умовного оператору?</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\">  <span class=\"token comment\">// 🔴 Ми порушуємо перше правило, розміщуючи хук всередині умовного оператору</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>name <span class=\"token operator\">!==</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span> <span class=\"token function\">persistForm</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      localStorage<span class=\"token punctuation\">.</span><span class=\"token function\">setItem</span><span class=\"token punctuation\">(</span><span class=\"token string\">'formData'</span><span class=\"token punctuation\">,</span> name<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Умова <code class=\"gatsby-code-text\">name !== &#39;&#39;</code> дорівнює <code class=\"gatsby-code-text\">true</code> при першому рендері, тому цей хук буде виконано. Хай там що, та в наступному рендері користувач може очистити форму і таким чином змінити цю умову на <code class=\"gatsby-code-text\">false</code>. Тепер, оскільки ми пропускаємо цей хук під час рендеру, послідовність викликів хуків стає іншою:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\"><span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Ліна'</span><span class=\"token punctuation\">)</span>           <span class=\"token comment\">// 1. Зчитуємо змінну стану name (аргумент ігнорується)</span>\n<span class=\"token comment\">// useEffect(persistForm)  // 🔴 Цей хук пропущено!</span>\n<span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Костенко'</span><span class=\"token punctuation\">)</span>        <span class=\"token comment\">// 🔴 2 (але був 3). Помилка при зчитуванні змінної стану surname</span>\n<span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span>updateTitle<span class=\"token punctuation\">)</span>     <span class=\"token comment\">// 🔴 3 (but was 4). Помилка при зміні ефекту</span></code></pre></div>\n<p>React не знатиме, що повернути для другого виклику хуку <code class=\"gatsby-code-text\">useState</code>. React очікував, що другий виклик хуку в цьому компоненті відповідає ефекту <code class=\"gatsby-code-text\">persistForm</code> так само як і під час попереднього рендеру, але це більше не так. З цього моменту кожен наступний виклик хуку після того, що ми пропустили, також зміститься на один, що призведе до помилок.</p>\n<p><strong>Ось чому хуки мають викликатися на вищому рівні наших компонентів.</strong> Якщо ми хочемо викликати ефект за певної умови, то ми можемо розмістити цю умову <em>всередину</em> нашого хуку:</p>\n<div class=\"gatsby-highlight\" data-language=\"jsx\"><pre class=\"gatsby-code-jsx\"><code class=\"gatsby-code-jsx\">  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span> <span class=\"token function\">persistForm</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// 👍 Більше ми не порушимо перше правило</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>name <span class=\"token operator\">!==</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      localStorage<span class=\"token punctuation\">.</span><span class=\"token function\">setItem</span><span class=\"token punctuation\">(</span><span class=\"token string\">'formData'</span><span class=\"token punctuation\">,</span> name<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p><strong>Зауважте, що вам не потрібно буде піклуватися про цю проблему, якщо ви додасте до вашого проекту <a href=\"https://www.npmjs.com/package/eslint-plugin-react-hooks\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">запропоноване правило для лінтера</a>.</strong> Але тепер ви знаєте, <em>чому</em> хуки працюють таким чином, та які проблеми можна запобігти використовуючи це правило.</p>\n<h2 id=\"next-steps\"><a href=\"#next-steps\" aria-hidden class=\"anchor\"><svg aria-hidden=\"true\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Наступні кроки </h2>\n<p>Нарешті ми можемо почати вчитися тому, <a href=\"/docs/hooks-custom.html\">як писати користувацькі хуки</a>! Хуки користувача дозволять вам комбінувати хуки впроваджені React з вашими власними абстракціями та повторно використовувати загальну логіку стану між різними компонентами.</p>","frontmatter":{"title":"Правила хуків","next":"hooks-custom.html","prev":"hooks-effect.html"},"fields":{"path":"content/docs/hooks-rules.md","slug":"docs/hooks-rules.html"}}},"pageContext":{"slug":"docs/hooks-rules.html"}},"staticQueryHashes":[]}