کامپوننت‌های Higher Order (یا به اختصار HOC) از الگوهای قدرتمند در React محسوب می‌شوند که به توسعه‌دهندگان اجازه می‌دهند بدون نیاز به ویرایش مستقیم کامپوننت اصلی، قابلیت‌های جدیدی به آن اضافه کنند.
این الگوها راهکاری قابل‌استفاده‌ مجدد برای مدیریت دغدغه‌های مشترکی مانند احراز هویت، ثبت لاگ یا مدیریت state سراسری فراهم می‌کنند.

با وجود اینکه هوک‌ها تا حد زیادی جایگزین HOCها برای بازاستفاده از منطق شده‌اند، کامپوننت‌های Higher Order همچنان در برخی شرایط مزایای منحصربه‌فردی دارند؛ به ویژه هنگام کار با کدهای قدیمی یا زمانی که نیاز به ایجاد تغییرات پیچیده در رفتار کامپوننت‌ها وجود دارد.

HOC چیست و چه زمانی باید از آن استفاده کنیم؟

کامپوننت Higher Order در React، تابعی است که یک کامپوننت را به عنوان ورودی دریافت می‌کند و یک کامپوننت جدید و توسعه‌یافته را به عنوان خروجی بازمی‌گرداند.

هر دو الگوی HOC و هوک، منطق دارای state را در خود نگه‌ می‌دارند، اما این کار را به روش‌های متفاوتی انجام می‌دهند و برای موارد استفاده مختلفی مناسب هستند.

برای درک بهتر تفاوت میان این دو الگو، در ادامه یک ویژگی شمارنده ساده را با دو روش پیاده‌سازی کرده‌ایم: یکی با استفاده از HOC و دیگری با استفاده از یک هوک سفارشی.

روش اول: استفاده از HOC

// 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}
      />
    );
  };
};

روش دوم: استفاده از هوک سفارشی

// Custom Hook that provides counter functionality
const useCounter = () => {
  const [count, setCount] = useState(0);
  return {
    count,
    increment: () => setCount(prev => prev + 1)
  };
};

// Usage

const Counter = () => {
  const {count, increment} = useCounter();
  return (
      <>
        <button>Increment</button>
        <p>Clicked:{count}</p>
      </>
)
}

در حالی که هر دو روش عملکردی مشابه دارند، تفاوت اصلی آن‌ها در ساختار پیاده‌سازی است:
الگوی HOC یک کامپوننت موجود را درون یک کامپوننت دیگر قرار می‌دهد تا قابلیت‌های بیشتری به آن بیفزاید، در حالی که هوک سفارشی منطق قابل استفاده مجدد را جدا می‌کند و به شکلی تمیز، بدون تغییر در ساختار سلسله مراتبی کامپوننت، مورد استفاده قرار می‌گیرد.

ساختار یک کامپوننت Higher Order در React

طبق مستندات رسمی React، یک کامپوننت Higher Order معمولاً این‌گونه تعریف می‌شود:

«کامپوننت Higher Order در React تابعی است که یک کامپوننت را به عنوان ورودی دریافت کرده و یک کامپوننت جدید بازمی‌گرداند.»

اگر بخواهیم این تعریف را به صورت کدی بیان کنیم، به شکل زیر خواهد بود:

const newComponent = higherFunction(WrappedComponent);

در این خط کد:

ایجاد یک کامپوننت Higher Order در React

برای ساخت یک HOC، ابتدا باید تابعی تعریف کنیم که کامپوننت پایه را به عنوان آرگومان دریافت کرده و یک کامپوننت جدید با قابلیت‌های اضافه‌شده را بازگرداند.
در یک HOC فانکشنال می‌توانیم از هوک‌ها برای مدیریت state و side effectها استفاده کنیم. به عنوان مثال:

import React, { useState, useEffect } from 'react';

const withEnhancement = (BaseComponent) => {
  return function EnhancedComponent(props) {
    // HOC-specific logic using hooks
    return <BaseComponent {...props} />;
  };
};

توسعه کامپوننت

درون تابع EnhancedComponent می‌توانیم از هوک‌هایی مانند useState، useEffect و useRef برای مدیریت state و انجام عملیات جانبی استفاده کنیم تا رفتارهای جدیدی به کامپوننت اضافه شود:

const withEnhancement = (BaseComponent) => {
  return function EnhancedComponent(props) {
    const [count, setCount] = useState(0);

    useEffect(() => {
      // Perform side effects here
    }, [count]);

    return <BaseComponent count={count} setCount={setCount} {...props} />;
  };
};

نحوه استفاده از HOC

برای استفاده از HOC ساخته شده، کافی است کامپوننت پایه را به عنوان ورودی به تابع HOC ارسال کنیم. نتیجه، یک کامپوننت جدید با قابلیت‌های توسعه‌یافته خواهد بود:

const EnhancedComponent = withEnhancement(BaseComponent);

استفاده از کامپوننت توسعه یافته

کامپوننتی که با استفاده از HOC ساخته شده، مانند سایر کامپوننت‌های React قابل استفاده است، با این تفاوت که قابلیت‌های جدیدی از طریق HOC به آن اضافه شده‌اند:

function App() {
  return <EnhancedComponent />;
}

در بخش بعدی مقاله، به بررسی یک نمونه کاربردی از HOCها در عمل خواهیم پرداخت.

استفاده از کامپوننت‌های Higher Order در React

در این بخش به یک مثال عملی از استفاده از HOCها در پروژه‌های React می‌پردازیم.

راه‌اندازی repository پروژه

ابتدا باید یک پروژه خالی React ایجاد کنیم. برای این کار، دستورات زیر را اجرا می‌کنیم:

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 را به صورت عملی نمایش دهیم:

وارد پوشه components می‌شویم و این دو فایل را ایجاد می‌کنیم. در پایان، ساختار فایل‌های پروژه باید به شکل زیر باشد:

📁 public
📁 src
  📁 components
    📄 ClickIncrease.js
    📄 HoverIncrease.js
📄 App.js
📄 index.js
📄 styles.css
📄 package.json

کدنویسی کامپوننت‌ها

در فایل ClickIncrease.js کد زیر را می‌نویسیم:

// File: components/ClickIncrease.js
import React, { useState } from 'react';

function ClickIncrease() {
  const [fontSize, setFontSize] = useState(10); // Set initial value to 10.

  return (
    <button onClick={() => setFontSize(size => size + 1)}>
      Increase with click
    </button>
    <p style={{ fontSize: `${fontSize}px` }}>
      Size of font: {fontSize}px
    </p>
  );
}

export default ClickIncrease;

سپس در فایل HoverIncrease.js کد زیر را قرار می‌دهیم:

// File: components/HoverIncrease.js
import React, { useState } from 'react';

function HoverIncrease() {
  const [fontSize, setFontSize] = useState(10);

  return (
    <div onMouseOver={() => setFontSize(size => size + 1)}>
      <p style={{ fontSize: `${fontSize}px` }}>
        Size of font: {fontSize}px
      </p>
    </div>
  );
}

export default HoverIncrease;

استفاده از کامپوننت‌ها در فایل App.js

در نهایت، برای نمایش این دو کامپوننت در رابط کاربری، آن‌ها را در فایل App.js رندر می‌کنیم:

// 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، فایلی با نام withCounter.js ایجاد کرده، سپس کد ابتدایی زیر را در آن قرار می‌دهیم:

import React from "react";
const UpdatedComponent = (OriginalComponent) => {
function NewComponent(props) {
//render OriginalComponent and pass on its props.
return ;
}
return NewComponent;
};
export default UpdatedComponent;

بررسی جزئیات کد

در ابتدا، تابعی به نام UpdatedComponent تعریف شده است که به عنوان ورودی، یک آرگومان به نام OriginalComponent دریافت می‌کند. این آرگومان همان کامپوننت React است که قصد داریم آن را با قابلیت‌های جدید wrap کنیم.

در مرحله بعد، به React دستور داده‌ایم که OriginalComponent را در رابط کاربری رندر کند. پیاده‌سازی قابلیت‌های افزوده را در ادامه مقاله انجام خواهیم داد.

استفاده از تابع HOC در کامپوننت‌ها

برای استفاده از HOC ایجاد شده، ابتدا وارد فایل HoverIncrease.js می‌شویم و کد زیر را به آن اضافه می‌کنیم:

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 را با تابع withCounter wrap کرده‌ایم تا به یک کامپوننت Higher Order تبدیل شود.

سپس، دقیقاً همان مراحل را برای ماژول ClickIncrease نیز انجام می‌دهیم:

//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، مقدار name را به صورت prop به کامپوننت داخلی منتقل می‌کنیم:

// File: components/withCounter.js
const UpdatedComponent = (OriginalComponent) => {
  function NewComponent(props) {
    return <OriginalComponent name="LogRocket" {...props} />;
  }
  return NewComponent;
};
export default UpdatedComponent;

استفاده از prop در کامپوننت‌های child

اکنون فایل‌های HoverIncrease.js و ClickIncrease.js را به گونه‌ای ویرایش می‌کنیم که مقدار prop جدید را نمایش دهند:

// 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، یک HOC تعریف می‌کنیم که یک state counter و یک تابع incrementCounter را مدیریت می‌کند:

// File: components/withCounter.js
import React, { useState } from 'react';

const withCounter = (OriginalComponent) => {
  function NewComponent(props) {
    const [counter, setCounter] = useState(10) // Initialize counter state

    return (
      <OriginalComponent
        counter={counter}
        incrementCounter={() => setCounter(counter + 1)}
        {...props}
      />
    )
  }
  return NewComponent
};

export default withCounter;

توضیح کد:

استفاده از HOC در کامپوننت‌های child

کامپوننت‌های HoverIncrease و ClickIncrease را برای استفاده از state و تابع مشترک تغییر می‌دهیم:

// 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 را با یک عدد دلخواه افزایش دهیم، چه کاری باید انجام دهیم؟
خوشبختانه، با استفاده از HOCها، می‌توانیم داده‌های خاصی مانند یک مقدار عددی مشخص را نیز به کامپوننت‌های child منتقل کنیم. این قابلیت از طریق ارسال پارامترها به تابع HOC فراهم می‌شود.

فعال‌سازی پشتیبانی از پارامترها

برای افزودن این قابلیت، ابتدا فایل components/withCounter.js را به گونه‌ای تغییر می‌دهیم که یک پارامتر جدید به نام increaseCount را بپذیرد:

//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)، یک پارامتر عددی به نام increaseCount نیز دریافت خواهد کرد.
از این پارامتر برای تعیین میزان افزایش مقدار counter استفاده می‌شود.

استفاده از پارامترها در کامپوننت‌های child

کامپوننت‌های HoverIncrease و ClickIncrease را برای استفاده از این پارامتر، به‌روزرسانی می‌کنیم:

//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) به HOC، می‌توانیم رفتار افزایش را در هر کامپوننت wrap شده به صورت داینامیک کنترل نماییم.

در نهایت، فایل withCounter.js باید به شکل زیر باشد:

import React from "react";
import { useState } from "react";
const UpdatedComponent = (OriginalComponent, increaseCount) => {
function NewComponent(props) {
const [counter, setCounter] = useState(10);
return (
name="LogRocket"
counter={counter}
incrementCounter={() => setCounter((size) => size + increaseCount)}
/>
);
}
return NewComponent;
};
export default UpdatedComponent;

فایل HoverIncrease.js نیز باید به صورت زیر باشد:

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 ما باید کد زیر را داشته باشد:

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 استفاده می‌کنیم زمانی که نیاز داریم:

از هوک استفاده می‌کنیم زمانی که نیاز داریم:

سازمان‌دهی کد

الگوهای مدرن پیاده‌سازی

در بسیاری از پروژه‌های امروزی، از ترکیب HOC و هوک برای ساختاردهی بهتر و انعطاف‌پذیری بیشتر استفاده می‌شود.

نمونه واقعی: احراز هویت

در مثال زیر، از یک HOC با استفاده از یک هوک سفارشی (useAuth) برای کنترل دسترسی به یک داشبورد ادمین استفاده شده است:

// Authentication HOC
const withAuth = (WrappedComponent, requiredRole) => {
  return function AuthWrapper(props) {
    const { isAuthenticated, userRole } = useAuth(); // Custom hook for auth state
    const navigate = useNavigate();

    useEffect(() => {
      if (!isAuthenticated) {
        navigate('/login');
      } else if (requiredRole && userRole !== requiredRole) {
        navigate('/unauthorized');
      }
    }, [isAuthenticated, userRole, navigate]);

    if (!isAuthenticated) {
      return null; // Optionally return a loader while determining authentication
    }

    return <WrappedComponent {...props} />;
  };
};

// Usage with a protected component
const AdminDashboard = ({ data }) => {
  return <div>Admin Dashboard Content</div>;
};

export default withAuth(AdminDashboard, 'admin');

مثال دیگر: بهینه‌سازی عملکرد با ترکیب هوک‌ها درون HOC

در مثال‌های پیچیده‌تر، می‌توانیم از هوک‌ها برای بهینه‌سازی عملکرد یا مدیریت منطق خاص درون HOC استفاده کنیم. به عنوان مثال:

// Performance optimization HOC using hooks
const withDataFetching = (WrappedComponent, fetchConfig) => {
  return function DataFetchingWrapper(props) {
    const [data, setData] = useState(null);
    const [error, setError] = useState(null);
    const [loading, setLoading] = useState(true);

    const { cache } = useCacheContext();
    const { notify } = useNotification();

    useEffect(() => {
      const fetchData = async () => {
        try {
          const cachedData = cache.get(fetchConfig.key);
          if (cachedData) {
            setData(cachedData);
            setLoading(false);
            return;
          }

          const response = await fetch(fetchConfig.url);
          const result = await response.json();

          cache.set(fetchConfig.key, result);
          setData(result);
        } catch (err) {
          setError(err);
          notify({
            type: 'error',
            message: 'Failed to fetch data',
          });
        } finally {
          setLoading(false);
        }
      };

      fetchData();
    }, [fetchConfig.url, fetchConfig.key]);

    return <WrappedComponent {...props} data={data} loading={loading} error={error} />;
  };
};

ملاحظات عملکردی

اگر HOC ما شامل محاسبات سنگین یا زمان‌بر باشد، پیشنهاد می‌شود از تکنیک‌هایی مانند حافظه‌سازی (Memoization) برای جلوگیری از رندرهای غیرضروری استفاده نماییم.

در مثال زیر، از useMemo و React.memo برای بهینه‌سازی عملکرد بهره گرفته‌ایم:

// 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 را ترکیب کنیم.

روش مستقیم ترکیب HOCها به شکل زیر می‌باشد:

const composedComponent = withAuth(withData(withLogging(BaseComponent)));

استفاده از تابع کمکی compose

همچنین، برای ترکیب توابع از راست به چپ، می‌توانیم از یک utility به‌نام compose استفاده کنیم (مشابه آنچه در کتابخانه‌هایی مانند Redux وجود دارد):

// Utility
const compose = (...functions) => x =>
  functions.reduceRight((acc, fn) => fn(acc), x);

// Usage
const composedComponent = compose(withAuth, withData, withLogging)(BaseComponent);

نکات کلیدی در ترکیب HOCها

Order matters

// These will behave differently:
const enhance1 = compose(withAuth, withDataFetching);
const enhance2 = compose(withDataFetching, withAuth);

Props flow

// Props flow through each HOC in the chain
const withProps = compose(
  withAuth,        // Adds isAuthenticated
  withDataFetching // Adds data, loading
);
// Final component receives: { isAuthenticated, data, loading, ...originalProps }

ملاحظات عملکردی

استفاده بیش از حد از ترکیب HOCها می‌تواند به افزایش پیچیدگی در درخت کامپوننت‌ها و کاهش عملکرد منجر شود.

const tooManyHOCs = compose(
  withAuth,
  withData,
  withLogging,
  withTheme,
  withTranslation,
  withRouter,
  withRedux
);
// Each layer adds complexity and potential performance impact

روش بهتر این است که دغدعه‌های مرتبط را در یک HOC ترکیب نماییم:

const withDataFeatures = compose(
  withData,
  withLoading,
  withError
);

const withAppFeatures = compose(
  withAuth,
  withAnalytics
);

Debugging

const withDebug = (WrappedComponent) => {
  return function DebugWrapper(props) {
    console.log('Component:', WrappedComponent.name);
    console.log('Props:', props);
    return <WrappedComponent {...props} />;
  };
};

const enhance = compose(
  withDebug, // Add at different positions to debug specific layers
  withAuth,
  withDebug,
  withDataFetching
);

ترکیب‌های قابل استفاده مجدد

const withDataProtection = compose(
  withAuth,
  withErrorBoundary,
  withLoading
);

const withAnalytics = compose(
  withTracking,
  withMetrics,
  withLogging
);

// Use them together or separately
const EnhancedComponent = compose(
  withDataProtection,
  withAnalytics
)(BaseComponent);

افزودن Type-Safety

استفاده از تایپ اسکریپت در پیاده‌سازی HOCها، خوانایی و نگه‌داری کد را به شکل چشمگیری بهبود می‌بخشد:

import React, { useState, useEffect } from 'react';

interface WithDataProps<T> {
  data: T | null;
  loading: boolean;
  error: Error | null;
}

interface FetchConfig {
  url: string;
}

function withData<T, P extends object>(
  WrappedComponent: React.ComponentType<P & WithDataProps<T>>,
  fetchConfig: FetchConfig
): React.FC<P> {
  return function WithDataComponent(props: P) {
    const [data, setData] = useState<T | null>(null);
    const [loading, setLoading] = useState<boolean>(true);
    const [error, setError] = useState<Error | null>(null);

    useEffect(() => {
      fetch(fetchConfig.url)
        .then((response) => response.json())
        .then((result: T) => {
          setData(result);
          setLoading(false);
        })
        .catch((err: Error) => {
          setError(err);
          setLoading(false);
        });
    }, [fetchConfig.url]);

    return (
      <WrappedComponent {...props} data={data} loading={loading} error={error} />
    );
  };
}

export default withData;

مشکل رایج در HOC: نحوه صحیح ارسال props

یکی از نکات مهم در استفاده از HOCها، نحوه صحیح ارسال props به کامپوننت child است. فرایند ارسال props در HOCها کمی متفاوت از کامپوننت‌های معمولی است.

برای مثال:

function App() {
return (
{/*Pass in a 'secretWord' prop*/}

);
}
function HoverIncrease(props) {
//read prop value:
console.log("Value of secretWord: " + props.secretWord);
//further code..
}

در این تئوری، باید در کنسول پیامی مشابه زیر مشاهده نماییم:

Value of secretWord: pineapple

اما در واقعیت، چنین چیزی چاپ نمی‌شود و Value of secretWord: undefined را در کنسول مشاهده می‌کنیم. علت این است که prop با نام secretWord به جای اینکه به کامپوننت HoverIncrease برسد، به تابع withCounter داده می‌شود و در ادامه به child منتقل نمی‌شود.

راه‌حل: اصلاح جزئی در فایل withCounter.js

برای حل این مشکل، تنها کافی است تمام props ورودی را به کامپوننت اصلی منتقل کنیم:

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ها در کنار هوک‌ها برای ایجاد معماری‌های مدرن و مقیاس‌پذیر بهره ببریم.