کامپوننتهای Higher Order (یا به اختصار HOC) از الگوهای قدرتمند در React محسوب میشوند که به توسعهدهندگان اجازه میدهند بدون نیاز به ویرایش مستقیم کامپوننت اصلی، قابلیتهای جدیدی به آن اضافه کنند. این الگوها راهکاری قابلاستفاده مجدد برای مدیریت دغدغههای مشترکی مانند احراز هویت، ثبت لاگ یا مدیریت state سراسری فراهم میکنند.
با وجود اینکه هوکها تا حد زیادی جایگزین HOCها برای بازاستفاده از منطق شدهاند، کامپوننتهای Higher Order همچنان در برخی شرایط مزایای منحصربهفردی دارند؛ به ویژه هنگام کار با کدهای قدیمی یا زمانی که نیاز به ایجاد تغییرات پیچیده در رفتار کامپوننتها وجود دارد.
HOC چیست و چه زمانی باید از آن استفاده کنیم؟
کامپوننت Higher Order در React، تابعی است که یک کامپوننت را به عنوان ورودی دریافت میکند و یک کامپوننت جدید و توسعهیافته را به عنوان خروجی بازمیگرداند.
هر دو الگوی HOC و هوک، منطق دارای state را در خود نگه میدارند، اما این کار را به روشهای متفاوتی انجام میدهند و برای موارد استفاده مختلفی مناسب هستند.
برای درک بهتر تفاوت میان این دو الگو، در ادامه یک ویژگی شمارنده ساده را با دو روش پیادهسازی کردهایم: یکی با استفاده از HOC و دیگری با استفاده از یک هوک سفارشی.
روش اول: استفاده از HOC
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// HOC that adds counter functionality to a component
const withCounter = (WrappedComponent)=>{
returnfunctionCounterWrapper(props){
const[count, setCount] = useState(0);
return(
<WrappedComponent
count={count}
increment={()=>setCount(prev => prev + 1)}
{...props}
/>
);
};
};
// HOC that adds counter functionality to a component
const withCounter = (WrappedComponent) => {
return function CounterWrapper(props) {
const [count, setCount] = useState(0);
return (
<WrappedComponent
count={count}
increment={() => setCount(prev => prev + 1)}
{...props}
/>
);
};
};
// HOC that adds counter functionality to a component
const withCounter = (WrappedComponent) => {
return function CounterWrapper(props) {
const [count, setCount] = useState(0);
return (
<WrappedComponent
count={count}
increment={() => setCount(prev => prev + 1)}
{...props}
/>
);
};
};
روش دوم: استفاده از هوکسفارشی
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Custom Hook that provides counter functionality
در حالی که هر دو روش عملکردی مشابه دارند، تفاوت اصلی آنها در ساختار پیادهسازی است:
الگوی HOC یک کامپوننت موجود را درون یک کامپوننت دیگر قرار میدهد تا قابلیتهای بیشتری به آن بیفزاید، در حالی که هوک سفارشی منطق قابل استفاده مجدد را جدا میکند و به شکلی تمیز، بدون تغییر در ساختار سلسله مراتبی کامپوننت، مورد استفاده قرار میگیرد.
ساختار یک کامپوننت Higher Order در React
طبق مستندات رسمی React، یک کامپوننت Higher Order معمولاً اینگونه تعریف میشود:
«کامپوننت Higher Order در React تابعی است که یک کامپوننت را به عنوان ورودی دریافت کرده و یک کامپوننت جدید بازمیگرداند.»
اگر بخواهیم این تعریف را به صورت کدی بیان کنیم، به شکل زیر خواهد بود:
WrappedComponent: کامپوننت پایهای است که قصد افزودن قابلیتهای جدید به آن داریم
ایجاد یک کامپوننت Higher Order در React
برای ساخت یک HOC، ابتدا باید تابعی تعریف کنیم که کامپوننت پایه را به عنوان آرگومان دریافت کرده و یک کامپوننت جدید با قابلیتهای اضافهشده را بازگرداند.
در یک HOC فانکشنال میتوانیم از هوکها برای مدیریت state و side effectها استفاده کنیم. به عنوان مثال:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import React, { useState, useEffect } from 'react';
const withEnhancement = (BaseComponent)=>{
returnfunctionEnhancedComponent(props){
// HOC-specific logic using hooks
return <BaseComponent {...props} />;
};
};
import React, { useState, useEffect } from 'react';
const withEnhancement = (BaseComponent) => {
return function EnhancedComponent(props) {
// HOC-specific logic using hooks
return <BaseComponent {...props} />;
};
};
import React, { useState, useEffect } from 'react';
const withEnhancement = (BaseComponent) => {
return function EnhancedComponent(props) {
// HOC-specific logic using hooks
return <BaseComponent {...props} />;
};
};
برای استفاده از HOC ساخته شده، کافی است کامپوننت پایه را به عنوان ورودی به تابع HOC ارسال کنیم. نتیجه، یک کامپوننت جدید با قابلیتهای توسعهیافته خواهد بود:
کامپوننتی که با استفاده از HOC ساخته شده، مانند سایر کامپوننتهای React قابل استفاده است، با این تفاوت که قابلیتهای جدیدی از طریق HOC به آن اضافه شدهاند:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
functionApp(){
return <EnhancedComponent />;
}
function App() {
return <EnhancedComponent />;
}
function App() {
return <EnhancedComponent />;
}
در بخش بعدی مقاله، به بررسی یک نمونه کاربردی از HOCها در عمل خواهیم پرداخت.
استفاده از کامپوننتهای Higher Order در React
در این بخش به یک مثال عملی از استفاده از HOCها در پروژههای React میپردازیم.
راهاندازی repository پروژه
ابتدا باید یک پروژه خالی React ایجاد کنیم. برای این کار، دستورات زیر را اجرا میکنیم:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npx create-react-app hoc-tutorial
cd hoc-tutorial #navigate to the project folder.
cd src #go to codebase
mkdir components #will hold all our custom components
npx create-react-app hoc-tutorial
cd hoc-tutorial #navigate to the project folder.
cd src #go to codebase
mkdir components #will hold all our custom components
npx create-react-app hoc-tutorial
cd hoc-tutorial #navigate to the project folder.
cd src #go to codebase
mkdir components #will hold all our custom components
در این مقاله، دو کامپوننت سفارشی ایجاد میکنیم تا کاربرد HOC را به صورت عملی نمایش دهیم:
ClickIncrease.js
ClickIncrease.js: این کامپوننت شامل یک دکمه و یک متن است. با کلیک روی دکمه (event
onClick
onClick)، مقدار ویژگی
fontSize
fontSize متن افزایش مییابد.
HoverIncrease.js
HoverIncrease.js: مشابه
ClickIncrease
ClickIncrease است، با این تفاوت که با رویداد
onMouseOver
onMouseOver واکنش نشان میدهد.
وارد پوشه
components
components میشویم و این دو فایل را ایجاد میکنیم. در پایان، ساختار فایلهای پروژه باید به شکل زیر باشد:
در نهایت، برای نمایش این دو کامپوننت در رابط کاربری، آنها را در فایل
App.js
App.js رندر میکنیم:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// File: App.js
import React from 'react';
import ClickIncrease from './components/ClickIncrease';
import HoverIncrease from './components/HoverIncrease';
functionApp(){
return(
<div>
<ClickIncrease />
<HoverIncrease />
</div>
);
}
exportdefault App;
// File: App.js
import React from 'react';
import ClickIncrease from './components/ClickIncrease';
import HoverIncrease from './components/HoverIncrease';
function App() {
return (
<div>
<ClickIncrease />
<HoverIncrease />
</div>
);
}
export default App;
// File: App.js
import React from 'react';
import ClickIncrease from './components/ClickIncrease';
import HoverIncrease from './components/HoverIncrease';
function App() {
return (
<div>
<ClickIncrease />
<HoverIncrease />
</div>
);
}
export default App;
ساخت و استفاده از تابع HOC
در پوشه
components
components، فایلی با نام
withCounter.js
withCounter.js ایجاد کرده، سپس کد ابتدایی زیر را در آن قرار میدهیم:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import React from "react";
const UpdatedComponent = (OriginalComponent)=>{
functionNewComponent(props){
//render OriginalComponent and pass on its props.
return ;
}
return NewComponent;
};
exportdefault UpdatedComponent;
import React from "react";
const UpdatedComponent = (OriginalComponent) => {
function NewComponent(props) {
//render OriginalComponent and pass on its props.
return ;
}
return NewComponent;
};
export default UpdatedComponent;
import React from "react";
const UpdatedComponent = (OriginalComponent) => {
function NewComponent(props) {
//render OriginalComponent and pass on its props.
return ;
}
return NewComponent;
};
export default UpdatedComponent;
بررسی جزئیات کد
در ابتدا، تابعی به نام
UpdatedComponent
UpdatedComponent تعریف شده است که به عنوان ورودی، یک آرگومان به نام
OriginalComponent
OriginalComponent دریافت میکند. این آرگومان همان کامپوننت React است که قصد داریم آن را با قابلیتهای جدید wrap کنیم.
در مرحله بعد، به React دستور دادهایم که
OriginalComponent
OriginalComponent را در رابط کاربری رندر کند. پیادهسازی قابلیتهای افزوده را در ادامه مقاله انجام خواهیم داد.
استفاده از تابع HOC در کامپوننتها
برای استفاده از HOC ایجاد شده، ابتدا وارد فایل
HoverIncrease.js
HoverIncrease.js میشویم و کد زیر را به آن اضافه میکنیم:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import withCounter from "./withCounter.js"//import the withCounter function
//..further code ..
functionHoverIncrease(){
//..further code
}
//replace your 'export' statement with:
exportdefaultwithCounter(HoverIncrease);
//We have now converted HoverIncrease to an HOC function.
import withCounter from "./withCounter.js" //import the withCounter function
//..further code ..
function HoverIncrease() {
//..further code
}
//replace your 'export' statement with:
export default withCounter(HoverIncrease);
//We have now converted HoverIncrease to an HOC function.
import withCounter from "./withCounter.js" //import the withCounter function
//..further code ..
function HoverIncrease() {
//..further code
}
//replace your 'export' statement with:
export default withCounter(HoverIncrease);
//We have now converted HoverIncrease to an HOC function.
در این قطعه کد،
HoverIncrease
HoverIncrease را با تابع
withCounter
withCounter wrap کردهایم تا به یک کامپوننت Higher Order تبدیل شود.
سپس، دقیقاً همان مراحل را برای ماژول
ClickIncrease
ClickIncrease نیز انجام میدهیم:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//file name: components/ClickIncrease.js
import withCounter from "./withCounter";
functionClickIncrease(){
//...further code
}
exportdefaultwithCounter(ClickIncrease);
//ClickIncrease is now a wrapped component of the withCounter method.
//file name: components/ClickIncrease.js
import withCounter from "./withCounter";
function ClickIncrease() {
//...further code
}
export default withCounter(ClickIncrease);
//ClickIncrease is now a wrapped component of the withCounter method.
//file name: components/ClickIncrease.js
import withCounter from "./withCounter";
function ClickIncrease() {
//...further code
}
export default withCounter(ClickIncrease);
//ClickIncrease is now a wrapped component of the withCounter method.
اشتراکگذاری props بین کامپوننتها
یکی از ویژگیهای کلیدی یک کامپوننت Higher Order در React، قابلیت اشتراکگذاری props میان کامپوننتهای wrap شده است.
افزودن prop به HOC
در فایل
withCounter.js
withCounter.js، مقدار
name
name را به صورت prop به کامپوننت داخلی منتقل میکنیم:
ClickIncrease.js را به گونهای ویرایش میکنیم که مقدار prop جدید را نمایش دهند:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// File: components/HoverIncrease.js
functionHoverIncrease(props){
return(
<div>
Value of 'name'in HoverIncrease: {props.name}
</div>
);
}
exportdefaultwithCounter(HoverIncrease);
// File: components/ClickIncrease.js
functionClickIncrease(props){
return(
<div>
Value of 'name'in ClickIncrease: {props.name}
</div>
);
}
exportdefaultwithCounter(ClickIncrease);
// File: components/HoverIncrease.js
function HoverIncrease(props) {
return (
<div>
Value of 'name' in HoverIncrease: {props.name}
</div>
);
}
export default withCounter(HoverIncrease);
// File: components/ClickIncrease.js
function ClickIncrease(props) {
return (
<div>
Value of 'name' in ClickIncrease: {props.name}
</div>
);
}
export default withCounter(ClickIncrease);
// File: components/HoverIncrease.js
function HoverIncrease(props) {
return (
<div>
Value of 'name' in HoverIncrease: {props.name}
</div>
);
}
export default withCounter(HoverIncrease);
// File: components/ClickIncrease.js
function ClickIncrease(props) {
return (
<div>
Value of 'name' in ClickIncrease: {props.name}
</div>
);
}
export default withCounter(ClickIncrease);
همانطور که مشاهده میکنیم، با استفاده از HOCها میتوان به سادهترین شکل ممکن props مشترک را میان چندین کامپوننت به اشتراک گذاشت. این رویکرد در توسعه کامپوننتهای مقیاسپذیر و قابل استفاده مجدد، نقش کلیدی ایفا میکند.
اشتراکگذاری متغیرهای state با استفاده از هوکها
مشابه props، ما میتوانیم state و توابع تغییر آن را هم از طریق HOC بین کامپوننتها به اشتراک بگذاریم. این کار باعث میشود تا منطق مشترک به صورت ماژولار و قابل استفاده مجدد نوشته شود.
پیادهسازی HOC
در فایل
components/withCounter.js
components/withCounter.js، یک HOC تعریف میکنیم که یک state
counter
counter و یک تابع
incrementCounter
incrementCounter را مدیریت میکند:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// File: components/withCounter.js
import React, { useState } from 'react';
const withCounter = (OriginalComponent)=>{
functionNewComponent(props){
const[counter, setCounter] = useState(10)// Initialize counter state
ارسال props: مقدار state و تابع تغییر آن به عنوان props به کامپوننت wrap شده ارسال میشوند.
استفاده از HOC در کامپوننتهای child
کامپوننتهای
HoverIncrease
HoverIncrease و
ClickIncrease
ClickIncrease را برای استفاده از state و تابع مشترک تغییر میدهیم:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// File: components/HoverIncrease.js
import withCounter from './withCounter'
functionHoverIncrease(props){
return(
<div onMouseOver={props.incrementCounter}>
<p>Value of 'counter'in HoverIncrease: {props.counter}</p>
</div>
)
}
exportdefaultwithCounter(HoverIncrease)
// File: components/ClickIncrease.js
import withCounter from './withCounter'
functionClickIncrease(props){
return(
<button onClick={props.incrementCounter}>
Increment counter
</button>
<p>Value of 'counter'in ClickIncrease: {props.counter}</p>
)
}
exportdefaultwithCounter(ClickIncrease)
// File: components/HoverIncrease.js
import withCounter from './withCounter'
function HoverIncrease(props) {
return (
<div onMouseOver={props.incrementCounter}>
<p>Value of 'counter' in HoverIncrease: {props.counter}</p>
</div>
)
}
export default withCounter(HoverIncrease)
// File: components/ClickIncrease.js
import withCounter from './withCounter'
function ClickIncrease(props) {
return (
<button onClick={props.incrementCounter}>
Increment counter
</button>
<p>Value of 'counter' in ClickIncrease: {props.counter}</p>
)
}
export default withCounter(ClickIncrease)
// File: components/HoverIncrease.js
import withCounter from './withCounter'
function HoverIncrease(props) {
return (
<div onMouseOver={props.incrementCounter}>
<p>Value of 'counter' in HoverIncrease: {props.counter}</p>
</div>
)
}
export default withCounter(HoverIncrease)
// File: components/ClickIncrease.js
import withCounter from './withCounter'
function ClickIncrease(props) {
return (
<button onClick={props.incrementCounter}>
Increment counter
</button>
<p>Value of 'counter' in ClickIncrease: {props.counter}</p>
)
}
export default withCounter(ClickIncrease)
با وجود اینکه HOCها امکان اشتراک منطق و state را فراهم میکنند، اما بین نسخههای مختلف یک کامپوننت wrap شده، state به اشتراک گذاشته نمیشود.
اگر نیاز به state سراسری در کل اپلیکیشن داریم، بهتر است از Context API استفاده کنیم.
ارسال پارامترها
اگرچه در حال حاضر کد ما به درستی عمل میکند، اما یک سناریو را در نظر میگیریم؛ اگر بخواهیم مقدار متغیر
counter
counter را با یک عدد دلخواه افزایش دهیم، چه کاری باید انجام دهیم؟
خوشبختانه، با استفاده از HOCها، میتوانیم دادههای خاصی مانند یک مقدار عددی مشخص را نیز به کامپوننتهای child منتقل کنیم. این قابلیت از طریق ارسال پارامترها به تابع HOC فراهم میشود.
فعالسازی پشتیبانی از پارامترها
برای افزودن این قابلیت، ابتدا فایل
components/withCounter.js
components/withCounter.js را به گونهای تغییر میدهیم که یک پارامتر جدید به نام
increaseCount
increaseCount را بپذیرد:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//This function will now accept an 'increaseCount' parameter.
//This function will now accept an 'increaseCount' parameter.
const UpdatedComponent = (OriginalComponent, increaseCount) => {
function NewComponent(props) {
return (
//this time, increment the 'size' variable by 'increaseCount'
incrementCounter={() => setCounter((size) => size + increaseCount)}
/>
);
//further code..
//This function will now accept an 'increaseCount' parameter.
const UpdatedComponent = (OriginalComponent, increaseCount) => {
function NewComponent(props) {
return (
//this time, increment the 'size' variable by 'increaseCount'
incrementCounter={() => setCounter((size) => size + increaseCount)}
/>
);
//further code..
در این قطعه کد، به React اطلاع دادهایم که تابع ما اکنون علاوه بر کامپوننت اصلی (
OriginalComponent
OriginalComponent)، یک پارامتر عددی به نام
increaseCount
increaseCount نیز دریافت خواهد کرد.
از این پارامتر برای تعیین میزان افزایش مقدار
counter
counter استفاده میشود.
استفاده از پارامترها در کامپوننتهای child
کامپوننتهای
HoverIncrease
HoverIncrease و
ClickIncrease
ClickIncrease را برای استفاده از این پارامتر، بهروزرسانی میکنیم:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//In HoverIncrease, change the 'export' statement:
exportdefaultwithCounter(HoverIncrease, 10); //value of increaseCount is 10.
//this will increment the 'counter' Hook by 10.
//In ClickIncrease:
exportdefaultwithCounter(ClickIncrease, 3); //value of increaseCount is 3.
//will increment the 'counter' state by 3 steps.
//In HoverIncrease, change the 'export' statement:
export default withCounter(HoverIncrease, 10); //value of increaseCount is 10.
//this will increment the 'counter' Hook by 10.
//In ClickIncrease:
export default withCounter(ClickIncrease, 3); //value of increaseCount is 3.
//will increment the 'counter' state by 3 steps.
//In HoverIncrease, change the 'export' statement:
export default withCounter(HoverIncrease, 10); //value of increaseCount is 10.
//this will increment the 'counter' Hook by 10.
//In ClickIncrease:
export default withCounter(ClickIncrease, 3); //value of increaseCount is 3.
//will increment the 'counter' state by 3 steps.
با ارسال یک مقدار سفارشی (
increaseCount
increaseCount) به HOC، میتوانیم رفتار افزایش را در هر کامپوننت wrap شده به صورت داینامیک کنترل نماییم.
import { useState } from "react";
import withCounter from "./withCounter";
function HoverIncrease(props) {
const [fontSize, setFontSize] = useState(10);
const { counter, incrementCounter } = props;
return (
setFontSize((size) => size + 1)}>
Increase on hover
Size of font in onMouseOver function: {fontSize}
Value of 'name' in HoverIncrease: {props.name}
incrementCounter()}>Increment counter
Value of 'counter' in HoverIncrease: {counter}
);
}
export default withCounter(HoverIncrease, 10);
import { useState } from "react";
import withCounter from "./withCounter";
function HoverIncrease(props) {
const [fontSize, setFontSize] = useState(10);
const { counter, incrementCounter } = props;
return (
setFontSize((size) => size + 1)}>
Increase on hover
Size of font in onMouseOver function: {fontSize}
Value of 'name' in HoverIncrease: {props.name}
incrementCounter()}>Increment counter
Value of 'counter' in HoverIncrease: {counter}
);
}
export default withCounter(HoverIncrease, 10);
و در نهایت، کامپوننت
ClickIncrease
ClickIncrease ما باید کد زیر را داشته باشد:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import{ useEffect, useState } from "react";
import withCounter from "./withCounter";
functionClickIncrease(props){
const{ counter, incrementCounter } = props;
const[fontSize, setFontSize] = useState(10);
return(
setFontSize((size)=> size + 1)}>
Increase with click
Size of font in onClick function: {fontSize}
Value of 'name'in ClickIncrease: {props.name}
incrementCounter()}>Increment counter
Value of 'counter'in ClickIncrease: {counter}
);
}
exportdefaultwithCounter(ClickIncrease, 3);
import { useEffect, useState } from "react";
import withCounter from "./withCounter";
function ClickIncrease(props) {
const { counter, incrementCounter } = props;
const [fontSize, setFontSize] = useState(10);
return (
setFontSize((size) => size + 1)}>
Increase with click
Size of font in onClick function: {fontSize}
Value of 'name' in ClickIncrease: {props.name}
incrementCounter()}>Increment counter
Value of 'counter' in ClickIncrease: {counter}
);
}
export default withCounter(ClickIncrease, 3);
import { useEffect, useState } from "react";
import withCounter from "./withCounter";
function ClickIncrease(props) {
const { counter, incrementCounter } = props;
const [fontSize, setFontSize] = useState(10);
return (
setFontSize((size) => size + 1)}>
Increase with click
Size of font in onClick function: {fontSize}
Value of 'name' in ClickIncrease: {props.name}
incrementCounter()}>Increment counter
Value of 'counter' in ClickIncrease: {counter}
);
}
export default withCounter(ClickIncrease, 3);
مقایسه HOC و Hook: کدام را انتخاب کنیم؟
انتخاب بین کامپوننت Higher Order و هوکها، بستگی به دو عامل کلیدی دارد:
نوع تغییر در کامپوننتها
نحوه سازماندهی کد
تغییر در ساختار کامپوننت
از HOC استفاده میکنیم زمانی که نیاز داریم:
رفتار رندرینگ کامپوننت را تغییر دهیم، مانند رندر مشروط بر اساس سطح دسترسی یا مجوز کاربر
دغدغههای عمومی مانند احراز هویت، ثبت لاگ، مدیریت خطا، یا رندرینگ شرطی را مدیریت کنیم
از هوک استفاده میکنیم زمانی که نیاز داریم:
منطق دارای state را بین کامپوننتها به اشتراک بگذاریم، مانند مدیریت فرمها یا دریافت داده، بدون اینکه سلسله مراتب کامپوننتها را تغییر دهیم
باside effectها مانند اشتراکگذاری داده، تایمرها یا فراخوانی API که باید در زمان Mount یا Update کامپوننت اجرا شوند، کار کنیم
سازماندهی کد
HOCها برای ایجاد Wrapperهای یکپارچه و مدیریت تغییرات پیچیده در ساختار کامپوننتها بسیار مناسب هستند.
هوکها به ما این امکان را میدهند تا منطقهای دارای state را به صورت کارآمد و قابل ترکیب بنویسیم، بدون نیاز به افزودن لایههای اضافی در درخت کامپوننتها.
الگوهای مدرن پیادهسازی
در بسیاری از پروژههای امروزی، از ترکیب HOC و هوک برای ساختاردهی بهتر و انعطافپذیری بیشتر استفاده میشود.
نمونه واقعی: احراز هویت
در مثال زیر، از یک HOC با استفاده از یک هوک سفارشی (
useAuth
useAuth) برای کنترل دسترسی به یک داشبورد ادمین استفاده شده است:
اگر HOC ما شامل محاسبات سنگین یا زمانبر باشد، پیشنهاد میشود از تکنیکهایی مانند حافظهسازی (Memoization) برای جلوگیری از رندرهای غیرضروری استفاده نماییم.
// Assume expensiveDataProcessing is an expensive function that processes props.data
const expensiveDataProcessing = (data) => {
// ...expensive computations...
return data; // Replace with the actual processed result
};
const withOptimizedData = (WrappedComponent) => {
function OptimizedDataWrapper(props) {
const memoizedProps = useMemo(() => ({
...props,
processedData: expensiveDataProcessing(props.data),
}), [props.data]);
return <WrappedComponent {...memoizedProps} />;
}
return React.memo(OptimizedDataWrapper);
};
export default withOptimizedData;
// Assume expensiveDataProcessing is an expensive function that processes props.data
const expensiveDataProcessing = (data) => {
// ...expensive computations...
return data; // Replace with the actual processed result
};
const withOptimizedData = (WrappedComponent) => {
function OptimizedDataWrapper(props) {
const memoizedProps = useMemo(() => ({
...props,
processedData: expensiveDataProcessing(props.data),
}), [props.data]);
return <WrappedComponent {...memoizedProps} />;
}
return React.memo(OptimizedDataWrapper);
};
export default withOptimizedData;
الگوهای رایج HOC و بهترین روشها
ترکیب چند HOC
زمانی که نیاز داریم یک کامپوننت پایه را با چندین موضوع مشترک (مانند احراز هویت، دریافت داده، مدیریت خطا، و آنالیتیکس) توسعه دهیم، میتوانیم چندین HOC را ترکیب کنیم.
//Pass down all incoming props to the HOC's children:
{...props}
/>
);
}
return NewComponent;
};
const UpdatedComponent = (OriginalComponent, increaseCount) => {
function NewComponent(props) {
return (
//Pass down all incoming props to the HOC's children:
{...props}
/>
);
}
return NewComponent;
};
const UpdatedComponent = (OriginalComponent, increaseCount) => {
function NewComponent(props) {
return (
//Pass down all incoming props to the HOC's children:
{...props}
/>
);
}
return NewComponent;
};
این تغییر کوچک، مشکل را به طور کامل برطرف میکند.
جمعبندی
در این مقاله، مفاهیم پایهای و پیشرفته مربوط به کامپوننتهای Higher Order در React را بررسی کردیم. HOCها ابزار قدرتمندی برای ساخت اپلیکیشنهای React با منطقهای قابلاستفاده مجدد هستند. با رعایت اصول بهینهسازی، ترکیب صحیح، و ساختاردهی حرفهای، میتوانیم از HOCها در کنار هوکها برای ایجاد معماریهای مدرن و مقیاسپذیر بهره ببریم.