الگوهای React: HOC در برابر Render Props در برابر Hooks (نگاه مدرن)

React در طول سال‌ها خیلی تغییر کرده است. خیلی از الگوهایی که زمانی پرکاربرد بودند جایشان را به جایگزین‌های ساده‌تر و قدرتمندتر داده‌اند. در این مقاله سه الگوی مهم را مقایسه می‌کنیم — Higher-Order Component (HOC)، Render Props و Hooks — با تمرکز بر اینکه کی از هر کدام استفاده کنیم، مثال کد، مزایا و معایب و بهترین روش‌های امروزی.

۱. Higher-Order Component (HOC)

HOC تابعی است که یک کامپوننت می‌گیرد و یک کامپوننت جدید و تقویت‌شده برمی‌گرداند.

function withLogger(Component) {
  return function WrappedComponent(props) {
    console.log("Props:", props);
    return <Component {...props} />;
  };
}

const EnhancedButton = withLogger(Button);

مزایا: مناسب برای دغدغه‌های مشترک مثل احراز هویت و لاگ‌گیری؛ منطق قابل استفاده دوباره در چندین کامپوننت.

معایب: جهنم Wrapperها (تودرتویی زیاد)، دیباگ سخت، تداخل props و ناآشنا بودن برای تازه‌کارها.

۲. Render Props

Render Props الگویی است که در آن کامپوننت state یا منطقش را با یک تابع که به عنوان prop پاس داده شده به اشتراک می‌گذارد. به جای اینکه مثل HOC کامپوننت را بپیچانید، تابعی پاس می‌دهید که تعیین می‌کند چه چیزی رندر شود.

کامپوننت یک تابع دریافت می‌کند و با آن تصمیم می‌گیرد چه چیزی رندر کند.

بیایید یک ردیاب ماوس بسازیم:

function MouseTracker({ render }) {
  const [position, setPosition] = React.useState({ x: 0, y: 0 });

  function handleMouseMove(e) {
    setPosition({ x: e.clientX, y: e.clientY });
  }

  return (
    <div style={{ height: "100vh" }} onMouseMove={handleMouseMove}>
      {render(position)}
    </div>
  );
}

function App() {
  return (
    <MouseTracker
      render={({ x, y }) => (
        <div>
          <h2>Mouse Position</h2>
          <p>X: {x}</p>
          <p>Y: {y}</p>
        </div>
      )}
    />
  );
}

چطور کار می‌کند

  1. MouseTracker state (منطق) را نگه می‌دارد.
  2. حرکت ماوس را دنبال می‌کند.
  3. درباره رابط کاربری تصمیم نمی‌گیرد.
  4. به جایش render(position) را صدا می‌زند.
  5. والد تعیین می‌کند رابط کاربری چه شکلی باشد.

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

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

معایب: توابع داخل JSX تودرتویی را شلوغ می‌کنند، در ترکیب‌های عمیق خواندنش سخت است، ممکن است به پیچیدگی رابط کاربری مبتنی بر Callback برسد و در بیشتر موارد Hooks جایش را گرفته‌اند.

امروزه Render Props بیشتر در کتابخانه‌ها (نسخه‌های قدیمی React Router، کتابخانه‌های انیمیشن)، کامپوننت‌های دریافت داده، کدهای قدیمی و برخی ترکیب‌های پیشرفته رابط کاربری دیده می‌شود.

۳. Hooks (رویکرد مدرن React)

Hooks شیوه جدیدی از فکر کردن را معرفی کردند: به جای سازمان‌دهی کد حول چرخه عمر یا الگوهای Wrapper، منطق را حول توابع قابل استفاده دوباره سازمان می‌دهیم. می‌توانید منطق stateدار را بدون تغییر سلسله‌مراتب کامپوننت‌ها جدا کنید و دوباره به کار ببرید — تغییری از پیچاندن کامپوننت‌ها به ترکیب منطق از طریق توابع.

function useMousePosition() {
  const [position, setPosition] = React.useState({ x: 0, y: 0 });

  React.useEffect(() => {
    const handler = (e) => setPosition({ x: e.clientX, y: e.clientY });
    window.addEventListener("mousemove", handler);
    return () => window.removeEventListener("mousemove", handler);
  }, []);

  return position;
}

function App() {
  const position = useMousePosition();
  return <h1>{position.x}, {position.y}</h1>;
}

چرا Hooks، React را تغییر داد

  • بدون کامپوننت Wrapper (برخلاف HOC)
  • بدون توابع رندر تودرتو (برخلاف Render Props)
  • منطق ترکیب‌پذیر و قابل استفاده دوباره می‌شود
  • جداسازی بهتر رابط کاربری از رفتار

نقاط قوت: ساختار تمیز و مینیمال، ترکیب آسان چند واحد منطق، استفاده دوباره بالا با هوک‌های سفارشی، خوانایی در کدهای متوسط و بزرگ و بهترین هماهنگی با اکوسیستم مدرن React.

محدودیت‌ها: باید قوانین Hooks را رعایت کنید، استفاده بیش از حد از هوک‌های سفارشی منطق را تکه‌تکه می‌کند، طراحی انتزاع نظم می‌خواهد و اثرات جانبی اگر ساختار نداشته باشند پیچیده می‌شوند.

Hooks فقط یک بهبود نحوی نیستند؛ تغییری در مدل ذهنی‌اند، از وراثت و Wrapperها به ترکیب تابعی رفتار. به همین دلیل جای بیشتر کاربردهای HOC و Render Props را گرفتند.

کی از کدام استفاده کنیم؟

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

از HOC استفاده کنید وقتی با سیستم‌های قدیمی یا کتابخانه‌های قدیمی‌ای کار می‌کنید که به آن نیاز دارند.

از Render Props استفاده کنید وقتی به تزریق پویای رابط کاربری از کتابخانه‌ها نیاز دارید یا با الگوهای ترکیب قدیمی سروکار دارید.

جمع‌بندی

در توسعه مدرن React، Hooks پایه طراحی کامپوننت شده‌اند. استفاده دوباره از منطق را ساده می‌کنند، پیچیدگی ساختاری را کم می‌کنند و شیوه تابعی‌تری برای فکر کردن درباره رابط کاربری فراهم می‌کنند.

الگوهای قدیمی‌تر مثل HOC و Render Props منسوخ نشده‌اند — هنوز در خیلی از کتابخانه‌ها و معماری‌های قدیمی وجود دارند و فهمیدنشان برای نگهداری کدهای واقعی مهم است. یک توسعه‌دهنده قوی React کسی نیست که فقط Hooks را بلد است؛ کسی است که می‌فهمد چرا Hooks جای الگوهای قبلی را گرفتند و کی آن الگوها هنوز منطقی‌اند.

در رابط‌های کاربری پیچیده — داشبوردها، ابزارهای طراحی یا تجربه‌های سه‌بعدی وب — Hooks پایه‌ای مقیاس‌پذیر برای سازمان‌دهی منطق تعامل، state و اثرات جانبی فراهم می‌کنند. تسلط بر آن‌ها بیشتر از آنکه درباره نحو باشد، درباره یاد گرفتن ساختاردهی رفتار در سیستم‌های فرانت‌اند مدرن است.