مهارت های React خود را بالا ببرید: نمایندگی رویداد استاد برای برنامه های نرم

توضیحات:
کشف جادوی نمایندگی رویداد در React! بیاموزید که چگونه این الگوی قدرتمند سردردهای عملکرد و نگهداری مشترک را در لیست های بزرگ حل می کند ، چرا React به طور پیش فرض از آن استفاده می کند و چگونه می توان با زحمت داده ها را از عناصر کلیک بازیابی کرد.
آیا تا به حال خود را در حال ساختن لیست باشکوهی از موارد ، شاید یک مدیر وظیفه ، یک کاتالوگ تجارت الکترونیکی یا یک جدول کاربر ساده پیدا کرده و سپس به یک ضربه محکم و ناگهانی ضربه بزنید؟ شما می خواهید هر ردیف یا مورد تعاملی باشد – شاید کلیک کردن روی یک کار ، آن را کامل کند ، یا کلیک کردن روی یک محصول شما را به صفحه جزئیات آن می برد. اولین غریزه شما ، و کاملاً معتبر ، ممکن است ضمیمه آن باشد onClick
کنترل کننده به هر مورد لیست.
// The "Intuitive" (but potentially problematic) way
function TaskItem({ task }) {
const handleClick = () => {
console.log(`Task "${task.name}" clicked!`);
// Do something with task.id
};
return (
<li onClick={handleClick}>
{task.name}
li>
);
}
function TaskList({ tasks }) {
return (
<ul>
{tasks.map(task => (
<TaskItem key={task.id} task={task} />
))}
ul>
);
}
این کار می کند ، درست است؟ کاملا برای یک لیست کوچک از 5-10 مورد ، شما چیزی را متوجه نمی شوید. اما تصور کنید که لیست شما به صدها یا حتی هزاران مورد منفجر می شود. هر یک
هزینه پنهان بیش از حد شنوندگان
هنگامی که یک شنونده رویداد جداگانه را به هر عنصر وصل می کنید ، اساساً چندین هزینه پنهان را متحمل می شوید:
- گرگ حافظه: هر شنونده رویداد مقدار کمی از حافظه را مصرف می کند. صدها یا هزاران آن را ضرب کنید و ردپای حافظه برنامه شما شروع به رشد می کند.
-
تخلیه عملکرد (تنظیم): مرورگر برای تنظیم و پاره کردن همه این شنوندگان فردی باید سخت تر کار کند. اگر لیست شما پویا باشد (موارد غالباً اضافه می شوند یا حذف می شوند) ، این سربار می تواند به یک تنگنا با عملکرد قابل توجه تبدیل شود.
-
درهم و برهمی کد: در حالی که React به انتزاع برخی از این موارد کمک می کند ، در جاوا اسکریپت وانیل ، مدیریت بسیاری از شنوندگان فردی ، به ویژه برای عناصر اضافه شده پویا ، می تواند به سرعت منجر به کد کثیف و سخت و سخت شود.
اینجاست نمایندگی مانند یک ابرقهرمان در حال جابجایی!
نمایندگی رویداد چیست؟ جادوی پشت صحنه
در هسته اصلی آن ، نمایندگی رویداد یک تکنیک هوشمندانه است که از طبیعی استفاده می کند event bubbling
مکانیسم DOM (مدل شیء سند).
به حباب های رویداد مانند این فکر کنید: وقتی روی یک عنصر خاص کلیک می کنید (مثلاً یک دکمه داخل یک مورد لیست) ، این رویداد فقط روی آن دکمه اتفاق نمی افتد و متوقف می شود. این “حباب بالا” – به این معنی document
وت window
اشیاء
نمایندگی رویداد با پیوست کردن مجرد شنونده رویداد به یک عنصر اجداد مشترک (والدین)، به جای اتصال شنوندگان فردی به هر کودک. هنگامی که یک رویداد در یکی از کودکان رخ می دهد ، به والدین حباب می شود. سپس شنونده والدین این رویداد را “صید” می کند و می گوید کدام کودک خاص در واقع آن را تحریک کرده است.
چرا React عاشق نمایندگی رویداد است (و شما هم باید!)
یکی از جالب ترین موارد در مورد React این است که به عنوان بخشی از سیستم رویداد مصنوعی خود از نمایندگی رویداد در زیر کاپوت استفاده می کند. حتی اگر بنویسید onClick
در مورد عناصر JSX فردی ، React شنوندگان رویداد DOM بومی را به هر یک از آنها وصل نمی کند. درعوض ، یک شنونده رویداد سطح بالا را به ریشه برنامه React شما متصل می کند (معمولاً document
شیء یا عنصری که برنامه React شما نصب شده است).
هنگامی که یک رویداد DOM آتش می گیرد ، سیستم رویداد مصنوعی React آن را رهگیری می کند ، آن را در مرورگرهای مختلف عادی می کند و سپس آن را بر اساس درخت مؤلفه داخلی خود به اجزای React مناسب اعزام می کند. این رفتار پیش فرض به این معنی است که برنامه های React اغلب از مزایای عملکرد نمایندگی رویداد لذت می برند بدون اینکه بخواهید صریحاً آن را برای هر سناریو تنظیم کنید.
مزایای آن واضح است:
- عملکرد و حافظه بهینه شده: کمتر شنوندگان DOM واقعی به معنای مصرف حافظه کمتر و ارائه سریع تر هستند.
- محتوای پویا را با زحمت کنترل می کند: اگر مواردی را از لیست خود اضافه یا حذف کنید ، شنونده مجرد به طور خودکار آنها را می پوشاند. نیازی به اضافه کردن یا حذف شنوندگان نیست!
- پاک کننده ، کد قابل نگهداری تر: تمرکز منطق رویداد ، مؤلفه های شما را مرتب تر و اشکال زدایی آسان تر می کند.
event.target
در مقابل event.currentTarget:
خصوصیات رویداد خود را بدانید!
هنگامی که یک رویداد به شنونده نماینده شما حباب می کند ، شیء رویداد (e
در e.target
) دو بخش مهم اطلاعات را به شما می دهد:
-
e.target:
این به عنصر دقیقی اشاره دارد که در ابتدا این رویداد را برانگیخته است. اگر روی یک کلیک کنیددر داخل
با
e.target
خواهد شد بشر -
e.currentTarget:
این به عنصری است که شنونده رویداد در واقع به آن وصل شده است. اگر شنونده را به, then
e.currentTarget
خواهد شد, regardless of which
درک این تمایز برای نمایندگی موفقیت آمیز رویداد مهم است.
سوال میلیون دلاری: گرفتن هر شیء در ردیف در نمایندگی رویداد کلیک کنید
بنابراین ، شما لیست خود را دریافت کرده اید ، از نمایندگی رویداد (یا به طور ضمنی با React یا صریح) استفاده می کنید ، و اکنون باید بدانید که کدام مورد خاص از آرایه شما کلیک شده است.
این جایی است که سفارشی است data-*
ویژگی ها مفید هستند!
استراتژی:
- یک شناسه را تعبیه کرد: هنگام ارائه هر مورد در آرایه خود ، یک شناسه منحصر به فرد (مانند شناسه یا فهرست) را در یک ویژگی داده-* در عنصر قابل کلیک قرار دهید (به عنوان مثال ،
- یا
). - بازیابی در کنترل کننده: در کنترل کننده رویداد خود در والدین ، از Event.Target استفاده کنید تا عنصری را که کلیک شده است بدست آورید و سپس برای بازیابی شناسه خود به ویژگی Dataset خود دسترسی پیدا کنید.
- شیء را پیدا کنید: برای یافتن شیء مربوطه در آرایه داده اصلی خود از آن شناسه استفاده کنید.
بیایید به چند نمونه نگاه کنیم:
مثال 1: لیست اصلی محصولات (با استفاده از
data-id
)
تصور کنید که شما مجموعه ای از اشیاء محصول را دارید:
// dummy data const products = [ { id: 'p1', name: 'Laptop', price: 1200 }, { id: 'p2', name: 'Mouse', price: 25 }, { id: 'p3', name: 'Keyboard', price: 75 }, ];
در اینجا نحوه تنظیم نمایندگی رویداد برای دریافت محصول کلیک شده آورده شده است:
// how product list work function ProductList({ products }) { const handleProductClick = (event) => { // Traverse up from event.target to find the element with data-product-id // This is important because the click might be on a child of the const listItem = event.target.closest('li[data-product-id]'); if (listItem) { // Ensure a list item was actually clicked const productId = listItem.dataset.productId; // Access data-product-id const clickedProduct = products.find(product => product.id === productId); if (clickedProduct) { console.log("Clicked product:", clickedProduct); // Navigate to product detail page, add to cart, etc. // Example: navigate(`/products/${clickedProduct.id}`); } } }; return ( <ul onClick={handleProductClick} style={{ cursor: 'pointer' }}> {products.map(product => ( <li key={product.id} data-product-id={product.id} style={{ padding: '8px', borderBottom: '1px solid #eee' }}> <h3>{product.name}h3> <p>${product.price}p> li> ))} ul> ); } // Usage in App.js function App() { const myProducts = [ { id: 'p1', name: 'Laptop', price: 1200 }, { id: 'p2', name: 'Mouse', price: 25 }, { id: 'p3', name: 'Keyboard', price: 75 }, { id: 'p4', name: 'Monitor', price: 300 }, { id: 'p5', name: 'Webcam', price: 50 }, ]; return ( <div> <h1>Our Productsh1> <ProductList products={myProducts} /> div> ); }
توضیح:
- ما قرار دادیم
onClick
کنترل کننده در(the parent).
- Each
data-product-id
ویژگی ، نگه داشتن منحصر به فرد خودproduct.id
بشر - درون
handleProductClick
، ما استفاده می کنیمevent.target.closest('li[data-product-id]')
بشر این یک روش فوق العاده مفید است که به دنبال نزدیکترین اجداد (از جمله خود) است که با انتخاب CSS مطابقت دارد. این مواردی را انجام می دهد که کاربر روی آن کلیک می کند
یا
inside the
- هنگامی که ما
listItem
، ما می توانیم دسترسی پیدا کنیمlistItem.dataset.productId
برای دریافت شناسه ما - بالاخره ،
products.find()
به ما کمک می کند تا شیء کامل محصول را از اصلی خود بازیابی کنیمproducts
آرایه
مثال 2: جدول تعاملی (با استفاده از
data-index
)
برای جداول ، استفاده از
index
همچنین می تواند یک گزینه مناسب باشد ، به خصوص اگر داده های شما برای داشتن شناسه های منحصر به فرد تضمین نشده باشد ، یا اگر سفارش از اهمیت ویژه ای برخوردار باشد.function UserTable({ users }) { const handleRowClick = (event) => { const tableRow = event.target.closest('tr[data-user-index]'); if (tableRow) { // data-index values are strings, so convert to number const userIndex = parseInt(tableRow.dataset.userIndex, 10); const clickedUser = users[userIndex]; // Direct access by index if (clickedUser) { console.log("Clicked user:", clickedUser); // Example: show user details modal } } }; return ( <table onClick={handleRowClick} style={{ width: '100%', borderCollapse: 'collapse', cursor: 'pointer' }}> <thead> <tr> <th>IDth> <th>Nameth> <th>Emailth> tr> thead> <tbody> {users.map((user, index) => ( <tr key={user.id} data-user-index={index} style={{ borderBottom: '1px solid #eee' }}> <td>{user.id}td> <td>{user.name}td> <td>{user.email}td> tr> ))} tbody> table> ); } // Usage in App.js function App() { const myUsers = [ { id: 201, name: 'Alice Smith', email: 'alice.s@example.com' }, { id: 202, name: 'Bob Johnson', email: 'bob.j@example.com' }, { id: 203, name: 'Charlie Brown', email: 'charlie.b@example.com' }, { id: 204, name: 'Diana Prince', email: 'diana.p@example.com' }, ]; return ( <div> <h1>User Directoryh1> <UserTable users={myUsers} /> div> ); }
تفاوت کلیدی با
data-index
:
- به جای
product.id
، ما استفاده می کنیمindex
(استدلال دوم ازmap
). - ما استفاده می کنیم
parseInt()
چون مقادیر ازdataset
همیشه رشته ها هستند. - ما می توانیم با استفاده از شیء مستقیم به شی دسترسی پیدا کنیم
users[userIndex]
از آنجا که شاخص آرایه را ذخیره کردیم. این به طور کلی سریعتر ازfind()
اما اگر سفارش آرایه پس از ارائه تغییر کند ، مقاومت کمتری دارد.
مثال 3: رسیدگی به اقدامات خاص در یک ردیف
اگر چندین عنصر قابل کلیک در یک ردیف واحد داشته باشید (به عنوان مثال ، “ویرایش” و “حذف دکمه ها)؟ هنوز هم می توانید از نمایندگی رویداد استفاده کنید!
function ActionList({ items }) { const handleItemAction = (event) => { const actionButton = event.target.closest('button[data-action]'); if (actionButton) { const itemId = actionButton.dataset.itemId; // Get item ID from button const actionType = actionButton.dataset.action; // Get action type (e.g., 'edit', 'delete') const targetItem = items.find(item => item.id === itemId); if (targetItem) { console.log(`Action: ${actionType} on item:`, targetItem); // Perform specific action based on actionType if (actionType === 'edit') { alert(`Editing ${targetItem.name}`); } else if (actionType === 'delete') { const confirmDelete = window.confirm(`Are you sure you want to delete ${targetItem.name}?`); if (confirmDelete) { alert(`${targetItem.name} deleted! (simulated)`); } } } } }; return ( <ul onClick={handleItemAction} style={{ listStyle: 'none', padding: 0 }}> {items.map(item => ( <li key={item.id} style={{ border: '1px solid #ccc', margin: '10px 0', padding: '10px' }}> <span>{item.name} - Status: {item.status}span> <div style={{ float: 'right' }}> {/* Attach item ID to buttons */} <button data-item-id={item.id} data-action="edit" style={{ marginRight: '5px' }}>Editbutton> <button data-item-id={item.id} data-action="delete">Deletebutton> div> li> ))} ul> ); } // Usage in App.js function App() { const myItems = [ { id: 'task1', name: 'Create Blog Post', status: 'In Progress' }, { id: 'task2', name: 'Schedule Meeting', status: 'Pending' }, { id: 'task3', name: 'Review PR', status: 'Done' }, ]; return ( <div> <h1>Task Managementh1> <ActionList items={myItems} /> div> ); }
کلیدی از این مثال:
- در
onClick
هنوز والدین است.
- Now, the
data-item-id
خود دکمه ها است ، و اطمینان می دهیم که می دانیم این عمل متعلق به کدام است. - جدید
data-action
ویژگی به ما می گوید چه نوع اقدامی را باید انجام دهیم. - ما استفاده می کنیم
event.target.closest('button[data-action]')
برای اطمینان از اینکه دکمه ای را برای یک عمل در نظر گرفته ایم. - سپس کنترل کننده از هر دو استفاده می کند
itemId
وتactionType
برای انجام منطق صحیح.
افکار نهایی
نمایندگی رویداد یک مفهوم اساسی در توسعه وب مدرن است و React آن را از طریق سیستم رویداد مصنوعی خود به زیبایی پذیرفته است. با درک چگونگی حباب وقایع و نحوه استفاده مؤثر
event.target
وتdata-*
ویژگی ها ، شما می توانید برنامه های واکنش دهنده ، قابل حفظ و ظریف تر را بنویسید ، به خصوص هنگام برخورد با لیست های بزرگ و پویا.بنابراین پیش بروید ، آن لیست ها را مجدداً بازپرداخت کنید و از مزایای یک تجربه کاربر نرم و صاف تر و کارآمدتر لذت ببرید!
برنامه نویسی مبارک!