Hook قابلیت جدیدی است که از نسخه 16.8 به React اضافه شده است و امکان استفاده از state و دیگر قابلیت های React را بدون استفاده از ساختار class ممکن می سازد.
Hook ها توابعی ساده هستند که این امکان را به ما می دهند از قابلیت های state و lifecycle در react بدون استفاده از ساختار class در کامپوننت هایی که به صورت تابع هستند استفاده کنیم. Hook ها در داخل class ها غیر قابل استفاده می باشند (توصیه نمی شود که کامپوننت های موجود را دوباره بازنویسی کنید اما می توانید در کامپوننت های جدید از Hook ها استفاده کنید).
React تعدادی Hook (همانند useState) را به صورت پیش فرض تهیه کرده است، اما شما می توانید Hook های مورد نظر خود را نوشته و استفاده کنید.
import React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button ={() => setCount(count + 1)}>Click me</button> </div> ); }
نکته: hook ها از نسخه 16.8 به بعد قابل استفاده می باشد زمانی که نسخه های قدیم را به این نسخه بروزرسانی می کنید سایر کتابخانه ها همانند React DOM را نیز بروزرسانی کنید.
استفاده از hook در پروژه های موجود محدودیتی از نظر سازگاری کد ایجاد نمی کند و می توانید بدون آنکه کدهای موجود را تغییری بدهید از hook ها در کامپوننت های جدید استفاده کنید.
مثال زیر یک شمارشگر را نمایش می دهد که با کلیک بر روی شیء تعیین شده مقدار شمارشگر یک واحد اضافه می شود:
import React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button ={() => setCount(count + 1)}>Click me</button> </div> ); }
در مثال بالا useState یک Hook می باشد. این تابع را داخل یک تابع کامپوننت فراخوانی می کنیم تا یک state محلی را به آن اضافه کنیم. React این state را بین فراخوانی های متعدد کامپوننت حفظ می کند. useState یک آرایه با دو عنصر بر می گرداند که عنصر اول مقدار فعلی state و عنصر دوم یک تابع برای بروزرسانی مقدار state می باشد. این تابع شبیه this.setState می باشد با این تفاوت که state قبلی و جدید را با هم ادغام نمی کند.
useState تنها یک پارامتر به عنوان مقدار اولیه state می گیرد. در مثال بالا مقدار اولیه 0 می باشد و سبب می شود شمارشگر از 0 آغاز می شود، توجه داشته باشید که بر خلاف this.state که مقدار باید حتما object باشد در اینجا مقدار state می تواند object یا هر نوع داده دیگری باشد. مقدار اولیه state تنها در فراخوانی اول کامپوننت استفاده می شود.
تعریف چند state در تابع:
از state hook می توانیم چندین بار در یک کامپوننت استفاده کنیم:
function ExampleWithManyStates() { // Declare multiple state variables! const [age, setAge] = useState(42); const [fruit, setFruit] = useState('banana'); const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]); // ... }
با استفاده از ساختار array destructuring می توانیم نام های دلخواه خود را برای مقدار بازگشتی از useState تعیین کنیم که خوانایی کد را افزایش می دهد.
شرح کامل استفاده از useState را می نوانید در اینجا مطالعه کنید.
به احتمال زیاد اعمالی مانند دریافت/ارسال داده، یا کار با DOM را در یک کامپوننت React انجام داده اید. این اعمال اصطلاحا "Side Effects" نامیده می شوند زیرا بر سایر کامپوننت ها نیز اثراتی دارند که در حین اجرای اولیه کامپوننت قابل انجام نیست.
با استفاده از useEffect امکان استفاده از اعمال side effect در کامپوننت تابعی ممکن می باشد. در واقع هدف معادلسازی استفاده از componentDidMount، componentDidUpdate و componentWillUnmount در کلاس React می باشد اما با این تفاوت که از یک متد استفاده شود.
برای نمونه در مثال زیر بعد از آپدیت DOM در کامپوننت React عنوان صفحه تغییر می کند:
import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // Similar to componentDidMount and componentDidUpdate: useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button ={() => setCount(count + 1)}>Click me</button> </div> ); }
هنگامی که useEffect را فراخوانی می کنیم به React می گوییم که تابع مشخص شده را بعد از اعمال تغییراتی در DOM اجرا کند. Effect ها در داخل کامپوننت ها تعریف می شود و بنابراین به prop ها و state ها دسترسی دارند. به صورت پیش فرض React بعد از هر فراخوانی (علاوه بر اولین فراخوانی) effect ها را اجرا می کند (در مورد چرخه حیات React و نحوه استفاده از آنها با effect در ادامه توضیح داده خواهد شد).
در Effect ها با برگرداندن یک تابع می توان تعیین کرد که چگونه حذف شوند. برای نمونه در کامپوننت زیر برای وضعیت آنلاین دوستان از effect ها استفاده شده و در تابع برگشتی آن effect لغو شده است.
import React, { useState, useEffect } from 'react'; function FriendStatus(props) { const [isOnline, setIsOnline] = useState(null); function handleStatusChange(status) { setIsOnline(status.isOnline); } useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline'; }
در مثال بالا React اجرای ChatAPI را لغو می کند زمانی که کامپوننت unmount می شود و همچنین قبل از اجرای دوباره در فراخوانی های متعدد کامپوننت.
همانند useState می توانید از چندین useEffect در یک کامپوننت استفاده کنید.
function FriendStatusWithCounter(props) { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); const [isOnline, setIsOnline] = useState(null); useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); function handleStatusChange(status) { setIsOnline(status.isOnline); } //….. }
Hook ها این امکان را به شما می دهند که سازماندهی side effect های مرتبط به هم را در یک بخش انجام دهید (همانند افزودن یا لغو یک effect) به جای آنکه در کلاس React آنها را در چرخه حیات های مختلف به صورت جداگانه بنویسید.
شرح کامل استفاده از useEffect را می نوانید در اینجا مطالعه کنید.
استفاده از hook ها تنها محدود به رعایت دو شرط می باشد:
نکته: React از linter plugin برای چک کردن این قواعد استفاده می کند تا حتما توسط توسعه دهنده رعایت شود.
منبع: reactjs.org