แนวทางปฏิบัติที่ดีที่สุดด้วย React Hooks
เผยแพร่แล้ว: 2022-03-10 React Hooks เป็นส่วนเสริมใหม่ใน React 16.8 ที่ให้คุณใช้สถานะและคุณสมบัติ React อื่น ๆ โดยไม่ต้องเขียนองค์ประกอบของ class
กล่าวอีกนัยหนึ่ง Hooks คือฟังก์ชันที่ให้คุณ "เชื่อมต่อ" สถานะ React และคุณสมบัติวงจรชีวิตจากส่วนประกอบของฟังก์ชันได้ (พวกมันไม่ทำงานภายในองค์ประกอบของ class
)
React มี Hooks ในตัวเช่น useState
คุณยังสามารถสร้าง Hooks ของคุณเองเพื่อใช้พฤติกรรมการเก็บสถานะซ้ำระหว่างส่วนประกอบต่างๆ ตัวอย่างด้านล่างแสดงตัวนับที่มีการจัดการสถานะโดยใช้ useState()
ทุกครั้งที่คุณคลิกที่ปุ่ม เราจะใช้ setCount()
เพื่ออัปเดตค่าการ count
ทีละ 1
ตัวอย่างนี้แสดงตัวนับที่มีค่าเป็น 0
เมื่อคุณคลิกปุ่ม มันจะเพิ่มค่าขึ้น 1
ค่าเริ่มต้นของส่วนประกอบถูกกำหนดโดยใช้ useState
const [count, setCount] = useState(0)
อย่างที่คุณเห็น เราตั้งค่าให้เป็น 0
จากนั้นเราใช้เมธอด onClick()
เพื่อเรียก setCount
เมื่อเราต้องการเพิ่มค่า
<button onClick={() => setCount(count + 1)}> Click me </button>
ก่อนการเปิดตัว React Hooks ตัวอย่างนี้จะใช้โค้ดหลายบรรทัดมากขึ้น เนื่องจากเราต้องใช้องค์ประกอบของ class
กฎของ React Hooks
ก่อนที่เราจะลงลึกในแนวทางปฏิบัติที่ดีที่สุด เราต้องเข้าใจกฎของ React Hooks ซึ่งเป็นแนวคิดพื้นฐานบางประการของแนวทางปฏิบัติที่นำเสนอในบทความนี้ด้วย
React Hooks เป็นฟังก์ชัน JavaScript แต่คุณต้องปฏิบัติตามกฎสองข้อเมื่อใช้งาน
- Call Hooks ที่ระดับบนสุด;
- เรียก Hooks จากส่วนประกอบ React เท่านั้น
หมายเหตุ : กฎสองข้อนี้ถูกนำมาใช้ใน React Hooks แทนที่จะเป็นส่วนหนึ่งของ JavaScript
ลองดูกฎเหล่านี้ในรายละเอียดเพิ่มเติม
Call Hooks ที่ระดับบนสุด
อย่าเรียก Hooks ในลูป เงื่อนไข หรือฟังก์ชันที่ซ้อนกัน ใช้ Hooks ที่ระดับบนสุดของฟังก์ชัน React ของคุณเสมอ การปฏิบัติตามกฎนี้ คุณต้องแน่ใจว่ามีการเรียก Hooks ในลำดับเดียวกันทุกครั้งที่แสดงผลส่วนประกอบ นั่นคือสิ่งที่ทำให้ React สามารถรักษาสถานะของ Hooks ได้อย่างถูกต้องระหว่างการเรียกใช้ useState
และ useEffect
หลายครั้ง
มาสร้างองค์ประกอบ Form
ซึ่งมีสองสถานะ:
-
accountName
-
accountDetail
สถานะเหล่านี้จะมีค่าเริ่มต้น เราจะใช้เบ็ด useEffect
เพื่อคงสถานะไว้กับที่จัดเก็บในเครื่องของเบราว์เซอร์ของเราหรือกับชื่อเอกสารของเรา
ตอนนี้ ส่วนประกอบนี้อาจจะสามารถจัดการสถานะได้สำเร็จ หากยังคงเหมือนเดิมระหว่างการเรียก useState
และ useEffect
หลายครั้ง
function Form() { // 1. Use the accountName state variable const [accountName, setAccountName] = useState('David'); // 2. Use an effect for persisting the form useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); // 3. Use the accountDetail state variable const [accountDetail, setAccountDetail] = useState('Active'); // 4. Use an effect for updating the title useEffect(function updateStatus() { document.title = accountName + ' ' + accountDetail; }); // ... }
หากลำดับของ Hooks เปลี่ยนไป (ซึ่งสามารถทำได้เมื่อมีการเรียกใช้แบบวนซ้ำหรือแบบมีเงื่อนไข) React จะมีปัญหาในการค้นหาวิธีรักษาสถานะของส่วนประกอบของเรา
// ------------ useState('David') // 1. Initialize the accountName state variable with 'David' useEffect(persistForm) // 2. Add an effect for persisting the form useState('Active') // 3. Initialize the accountdetail state variable with 'Active' useEffect(updateStatus) // 4. Add an effect for updating the status // ------------- // Second render // ------------- useState('David') // 1. Read the accountName state variable (argument is ignored) useEffect(persistForm) // 2. Replace the effect for persisting the form useState('Active') // 3. Read the accountDetail state variable (argument is ignored) useEffect(updateStatus) // 4. Replace the effect for updating the status // ...
นั่นคือคำสั่ง React ที่จะเรียก hooks ของเรา เนื่องจากคำสั่งยังคงเหมือนเดิม จึงจะสามารถรักษาสถานะของส่วนประกอบของเราได้ แต่จะเกิดอะไรขึ้นถ้าเราวาง Hook call ไว้ในเงื่อนไข
// We're breaking the first rule by using a Hook in a condition if (accountName !== '') { useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); }
เงื่อนไข accountName !== ''
เป็น true
ในการเรนเดอร์ครั้งแรก ดังนั้นเราจึงเรียกใช้ Hook นี้ อย่างไรก็ตาม ในการแสดงผลครั้งถัดไป ผู้ใช้อาจล้างแบบฟอร์ม ทำให้เงื่อนไข false
ตอนนี้เราข้าม Hook นี้ระหว่างการเรนเดอร์ ลำดับของการเรียก Hook จะแตกต่างออกไป:
useState('David') // 1. Read the accountName state variable (argument is ignored) // useEffect(persistForm) // This Hook was skipped! useState('Active') // 2 (but was 3). Fail to read the accountDetails state variable useEffect(updateStatus) // 3 (but was 4). Fail to replace the effect
React ไม่รู้ว่าจะส่งคืนอะไรสำหรับการเรียก useState
Hook ครั้งที่สอง React คาดว่าการเรียก Hook ครั้งที่สองในคอมโพเนนต์นี้จะสอดคล้องกับเอฟเฟ persistForm
เช่นเดียวกับในระหว่างการเรนเดอร์ครั้งก่อน — แต่จะไม่เป็นเช่นนั้นอีกต่อไป จากจุดนั้น ทุกๆ การโทรของ Hook
ครั้งถัดไปหลังจากที่เราข้ามไป จะเปลี่ยนทีละรายการ ซึ่งนำไปสู่ข้อบกพร่อง
นี่คือเหตุผลที่ต้องเรียก Hooks ที่ระดับบนสุดของส่วนประกอบของเรา หากเราต้องการเรียกใช้เอฟเฟกต์แบบมีเงื่อนไข เราสามารถใส่เงื่อนไขนั้น ไว้ใน Hook ของเราได้
หมายเหตุ : ตรวจสอบเอกสาร React Hook เพื่ออ่านเพิ่มเติมในหัวข้อนี้
เฉพาะ Call Hooks จาก React Components
อย่าเรียก Hooks จากฟังก์ชัน JavaScript ปกติ คุณสามารถเรียก Hooks จากส่วนประกอบฟังก์ชัน React แทนได้ มาดูความแตกต่างระหว่างฟังก์ชัน JavaScript และองค์ประกอบ React ด้านล่าง:
ฟังก์ชัน JavaScript
import { useState } = "react"; function toCelsius(fahrenheit) { const [name, setName] = useState("David"); return (5/9) * (fahrenheit-32); } document.getElementById("demo").innerHTML = toCelsius;
ที่นี่เรานำเข้า useState
hook จากแพ็คเกจ React จากนั้นจึงประกาศฟังก์ชั่นของเรา แต่สิ่งนี้ไม่ถูกต้องเนื่องจากไม่ใช่องค์ประกอบ React
ฟังก์ชันตอบสนอง
import React, { useState} from "react"; import ReactDOM from "react-dom"; function Account(props) { const [name, setName] = useState("David"); return <p>Hello, {name}! The price is <b>{props.total}</b> and the total amount is <b>{props.amount}</b></p> } ReactDom.render( <Account total={20} amount={5000} />, document.getElementById('root') );
แม้ว่าเนื้อความของทั้งคู่จะดูคล้ายกัน แต่ส่วนหลังจะกลายเป็นส่วนประกอบเมื่อเรานำเข้า React ลงในไฟล์ นี่คือสิ่งที่ทำให้เราสามารถใช้สิ่งต่าง ๆ เช่น JSX และ React hooks ภายในได้
หากคุณนำเข้า hook ที่คุณต้องการโดยไม่นำเข้า React (ซึ่งทำให้เป็นฟังก์ชันปกติ) คุณจะไม่สามารถใช้งาน Hook ที่คุณนำเข้าได้เนื่องจาก Hook สามารถเข้าถึงได้เฉพาะในส่วนประกอบ React
ตะขอเรียกจากตะขอแบบกำหนดเอง
Hook ที่กำหนดเองคือฟังก์ชัน JavaScript ที่มีชื่อขึ้นต้นด้วย use
และอาจเรียก Hooks อื่นๆ ตัวอย่างเช่น ใช้ useUserName
ด้านล่าง Hook แบบกำหนดเองที่เรียกใช้ useState
และ useEffect
hooks มันดึงข้อมูลจาก API วนซ้ำผ่านข้อมูลและเรียก setIsPresent()
หากชื่อผู้ใช้เฉพาะที่ได้รับมีอยู่ในข้อมูล API
export default function useUserName(userName) { const [isPresent, setIsPresent] = useState(false); useEffect(() => { const data = MockedApi.fetchData(); data.then((res) => { res.forEach((e) => { if (e.name === userName) { setIsPresent(true); } }); }); }); return isPresent; }
จากนั้นเราสามารถใช้ฟังก์ชันของ hook นี้ซ้ำในที่อื่นที่เราต้องการในแอปพลิเคชันของเรา ในสถานที่ดังกล่าว ยกเว้นเมื่อจำเป็น เราไม่ต้องเรียก useState
หรือ useEffect
อีกต่อไป
เมื่อทำตามกฎนี้ คุณจะมั่นใจได้ว่าตรรกะของ stateful ทั้งหมดในองค์ประกอบนั้นมองเห็นได้ชัดเจนจากซอร์สโค้ด
ปลั๊กอิน ESLint
ปลั๊กอิน ESLint ที่เรียกว่า eslint-plugin-react-hooks
บังคับใช้กฎข้างต้น สิ่งนี้มีประโยชน์ในการบังคับใช้กฎเมื่อทำงานในโครงการ ฉันแนะนำให้คุณใช้ปลั๊กอินนี้เมื่อทำงานในโครงการของคุณ โดยเฉพาะอย่างยิ่งเมื่อทำงานกับผู้อื่น คุณสามารถเพิ่มปลั๊กอินนี้ในโครงการของคุณหากคุณต้องการลอง:
// Your ESLint configuration { "plugins": [ // ... "react-hooks" ], "rules": { // ... "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies } }
ปลั๊กอินนี้รวมอยู่โดยค่าเริ่มต้นใน Create React App ดังนั้นคุณไม่จำเป็นต้องเพิ่มเข้าไปหากคุณบูตแอปพลิเคชัน React ของคุณโดยใช้ Create-React-App
คิดถึงในตะขอ
มาดูส่วนประกอบใน class
และส่วนประกอบที่ใช้งานได้โดยสังเขป (กับ Hooks) ก่อนดำดิ่งสู่แนวทางปฏิบัติที่ดีที่สุดของ Hooks สองสามข้อ
วิธีที่ง่ายที่สุดในการกำหนดองค์ประกอบใน React คือการเขียนฟังก์ชัน JavaScript ที่ส่งคืนองค์ประกอบ React:
function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
ส่วนประกอบ Welcome
ยอมรับ props
ซึ่งเป็นวัตถุที่มีข้อมูลและส่งกลับองค์ประกอบปฏิกิริยา จากนั้นเราสามารถนำเข้าและแสดงผลองค์ประกอบนี้ในองค์ประกอบอื่น
องค์ประกอบของ class
ใช้วิธีการเขียนโปรแกรมที่เรียกว่า Encapsulation ซึ่งโดยพื้นฐานแล้วหมายความว่าทุกอย่างที่เกี่ยวข้องกับองค์ประกอบคลาสจะอยู่ภายในนั้น เมธอดวงจรชีวิต ( constructors
, componentDidMount()
, render
และอื่น ๆ ) ทำให้ส่วนประกอบมีโครงสร้างที่คาดเดาได้
การห่อหุ้มเป็นหนึ่งในพื้นฐานของ OOP ( O bject- O riented P rogramming) หมายถึงการรวมกลุ่มของข้อมูลภายในวิธีการที่ทำงานกับข้อมูลนั้น และใช้เพื่อซ่อนค่าหรือสถานะของออบเจ็กต์ข้อมูลที่มีโครงสร้างภายในคลาส เพื่อป้องกันการเข้าถึงโดยตรงของบุคคลที่ไม่ได้รับอนุญาต
ด้วย Hooks องค์ประกอบของส่วนประกอบจะเปลี่ยนจากการเป็น Hooks ที่มีวงจรชีวิตร่วมกัน — เป็นฟังก์ชันที่มีการแสดงผลบางส่วนในตอนท้าย
ส่วนประกอบฟังก์ชัน
ตัวอย่างด้านล่างแสดงให้เห็นว่า Hooks แบบกำหนดเองสามารถนำมาใช้ในองค์ประกอบการทำงานได้อย่างไร (โดยไม่แสดงว่าเนื้อหาคืออะไร) อย่างไรก็ตาม สิ่งที่ทำหรือสามารถทำได้ไม่จำกัด อาจเป็นการสร้างอินสแตนซ์ของตัวแปรสถานะ ใช้บริบท สมัครส่วนประกอบเพื่อผลข้างเคียงต่างๆ — หรือทั้งหมดข้างต้นหากคุณใช้ hook แบบกำหนดเอง!
function { useHook{...}; useHook{...}; useHook{...}; return (
...); }
ส่วนประกอบของคลาส
องค์ประกอบ class
ต้องการให้คุณขยายจาก React.Component
และสร้างฟังก์ชันการ render
ซึ่งส่งคืนองค์ประกอบ React สิ่งนี้ต้องการรหัสเพิ่มเติมแต่จะให้ประโยชน์บางอย่างแก่คุณด้วย
class { constructor(props) {...} componentDidMount() {...} componentWillUnmount() {...} render() {...} }
มีประโยชน์บางอย่างที่คุณได้รับจากการใช้ส่วนประกอบการทำงานใน React:
- การแยกคอนเทนเนอร์และส่วนประกอบการนำเสนอจะง่ายกว่าเพราะคุณต้องคิดเพิ่มเติมเกี่ยวกับสถานะของส่วนประกอบหากคุณไม่มีสิทธิ์เข้าถึง
setState()
ในส่วนประกอบของคุณ - ส่วนประกอบ การทำงานอ่านและทดสอบได้ง่ายกว่า มาก เนื่องจากเป็นฟังก์ชัน JavaScript ธรรมดาที่ไม่มีสถานะหรือเบ็ดวงจรชีวิต
- คุณลงเอยด้วย รหัสน้อยลง
- ทีม React กล่าวว่าอาจมีการเพิ่ม ประสิทธิภาพ สำหรับส่วนประกอบการทำงานในเวอร์ชัน React ในอนาคต
สิ่งนี้นำไปสู่แนวปฏิบัติที่ดีที่สุดประการแรกเมื่อใช้ React Hooks
Hooks แนวทางปฏิบัติที่ดีที่สุด
1. ลดความซับซ้อนของตะขอของคุณ
การรักษา React Hooks ให้เรียบง่ายจะทำให้คุณมีอำนาจในการควบคุมและจัดการสิ่งที่เกิดขึ้นในส่วนประกอบตลอดอายุการใช้งานได้อย่างมีประสิทธิภาพ หลีกเลี่ยงการเขียน Hooks แบบกำหนดเองให้มากที่สุด คุณสามารถอินไลน์ useState()
หรือ useEffect()
แทนการสร้าง hook ของคุณเอง
หากคุณพบว่าตัวเองกำลังใช้ Hooks แบบกำหนดเองจำนวนมากที่เกี่ยวข้องกับการทำงาน คุณสามารถสร้าง hook แบบกำหนดเองที่ทำหน้าที่เป็นตัวห่อหุ้มสำหรับสิ่งเหล่านี้ มาดูส่วนประกอบการทำงานที่แตกต่างกันสองอย่างพร้อมขอเกี่ยวด้านล่าง
ส่วนประกอบการทำงาน v1
function { useHook(...); useHook(...); useHook(...); return( <div>...</div> ); }
ส่วนประกอบที่ทำงาน v2
function { useCustomHook(...); useHook(...); useHook(...); return( <div>...</div> ); }
v2 เป็นเวอร์ชันที่ดีกว่าเพราะช่วยให้ hook เรียบง่ายและ useHook
อื่น ๆ ทั้งหมดเป็นแบบอินไลน์ตามลำดับ ซึ่งช่วยให้เราสร้างฟังก์ชันการทำงานที่สามารถนำมาใช้ซ้ำได้กับส่วนประกอบต่างๆ และยังช่วยให้เราควบคุมและจัดการส่วนประกอบของเราได้อย่างมีประสิทธิภาพมากขึ้น แทนที่จะใช้ v1 ที่ส่วนประกอบของเราทิ้งขยะกับ Hooks คุณควรใช้ v2 ซึ่งจะทำให้การดีบักง่ายขึ้นและโค้ดของคุณสะอาดขึ้น
2. จัดระเบียบและจัดโครงสร้างตะขอของคุณ
ข้อดีอย่างหนึ่งของ React Hooks คือความสามารถในการเขียนโค้ดน้อยลงและอ่านง่าย ในบางกรณี ปริมาณของ useEffect()
และ useState()
ยังคงสร้างความสับสนได้ เมื่อคุณจัดองค์ประกอบของคุณให้เป็นระเบียบ มันจะช่วยในการอ่านและรักษาการไหลของส่วนประกอบของคุณอย่างสม่ำเสมอและคาดเดาได้ หาก Hooks แบบกำหนดเองของคุณซับซ้อนเกินไป คุณสามารถแยกย่อยเป็น Hooks แบบกำหนดเองย่อยได้เสมอ แยกตรรกะของส่วนประกอบของคุณไปยัง Hooks ที่กำหนดเองเพื่อให้โค้ดของคุณสามารถอ่านได้
3. ใช้ตัวอย่าง React Hooks
React Hooks Snippets เป็นส่วนขยาย Visual Studio Code เพื่อทำให้ React Hooks ง่ายขึ้นและเร็วขึ้น ปัจจุบันรองรับห้า hooks:
-
useState()
-
useEffect()
-
useContext()
-
useCallback()
-
useMemo()
มีการเพิ่มส่วนย่อยอื่น ๆ ด้วย ฉันได้ลองใช้งาน Hooks เหล่านี้แล้ว และเป็นหนึ่งในแนวทางปฏิบัติที่ดีที่สุดที่ฉันเคยใช้เป็นการส่วนตัวขณะทำงานกับ Hooks
คุณสามารถเพิ่มตัวอย่าง React Hooks ในโครงการของคุณได้สองวิธี:
- สั่งการ
เปิด VS Code Quick open ( Ctrl + P ) วางext install ALDuncanson.react-hooks-snippets
แล้วกด Enter - ตลาดส่วนขยาย
เปิด 'VS Code Extension Marketplace' ( Ctrl + Shift + X ) และค้นหา 'React Hook Snippets' จากนั้นมองหาไอคอน "Alduncanson"
ฉันขอแนะนำตัวอย่างแรก อ่านเพิ่มเติมเกี่ยวกับตัวอย่างข้อมูลได้ที่นี่ หรือตรวจสอบตัวอย่างข้อมูลล่าสุดของ Hooks ที่นี่
4. นำกฎของตะขอมาพิจารณา
พยายามนำกฎสองข้อของ Hooks ที่เราได้เรียนรู้มาพิจารณาก่อนหน้านี้เสมอในขณะที่ทำงานกับ React Hooks
- เรียก Hooks ของคุณที่ระดับบนสุดเท่านั้น อย่าเรียก Hooks ในลูป เงื่อนไข หรือฟังก์ชันที่ซ้อนกัน
- เรียกใช้ Hooks จากส่วนประกอบฟังก์ชัน React หรือจาก Hooks ที่กำหนดเองเสมอ อย่าเรียก Hooks จากฟังก์ชัน JavaScript ปกติ
ปลั๊กอิน ESlint ที่เรียกว่า eslint-plugin-react-hooks
บังคับใช้กฎสองข้อนี้ คุณสามารถเพิ่มปลั๊กอินนี้ในโครงการของคุณได้หากต้องการ ตามที่เราอธิบายไว้ข้างต้นในส่วนกฎของ hooks
แนวทางปฏิบัติที่ดีที่สุดยังไม่ได้รับการแก้ไขอย่างสมบูรณ์เนื่องจาก Hooks ยังค่อนข้างใหม่ ดังนั้นการยอมรับควรดำเนินการด้วยความระมัดระวังในการยอมรับเทคโนโลยีในยุคแรกๆ ด้วยเหตุนี้ Hooks จึงเป็นหนทางสู่อนาคตของ React
บทสรุป
ฉันหวังว่าคุณจะสนุกกับการกวดวิชานี้ เราได้เรียนรู้กฎสองข้อที่สำคัญที่สุดของ React Hooks และวิธีคิดอย่างมีประสิทธิภาพใน Hooks เราได้พิจารณาองค์ประกอบการทำงานและแนวทางปฏิบัติที่ดีที่สุดในการเขียน Hooks ด้วยวิธีที่ถูกต้องและมีประสิทธิภาพ กฎเกณฑ์สั้น ๆ เป็นสิ่งสำคัญที่จะทำให้พวกเขาเป็นเข็มทิศนำทางเมื่อเขียนกฎ หากคุณมีแนวโน้มที่จะลืม คุณสามารถใช้ปลั๊กอิน ESLint เพื่อบังคับใช้ได้
ฉันหวังว่าคุณจะใช้บทเรียนทั้งหมดที่ได้เรียนรู้ที่นี่ในโครงการ React ครั้งต่อไปของคุณ ขอให้โชคดี!
ทรัพยากร
- “แนะนำ Hooks” React Docs
- “ฟังก์ชันเทียบกับส่วนประกอบระดับในปฏิกิริยา” David Joch, Medium
- “สารผสมถือว่าเป็นอันตราย” Dan Abramov จาก React Blog
- “React Hooks: แนวทางปฏิบัติที่ดีที่สุดและการเปลี่ยนแปลงในความคิด” Bryan Manuele, Medium
- “ตัวอย่าง React Hooks สำหรับรหัส VS” Anthony Davis, Visual Code Marketplace