سوالی که ممکن است تاکنون با آن برخورد کرده باشیم این است که منظور از کامپوننت reusable در React چیست؟ ما می‌توانیم این کامپوننت‌ها را به عنوان بلاک‌های سازنده در نظر بگیریم. کامپوننت‌‌های reusable کدهای مستقلی هستند که می‌توانند در سرتاسر وب‌سایت ما به صورت مجدد استفاده شوند تا در وقت و تلاش ما صرفه جویی شود. آن‌ها می‌توانند هر چیزی، از دکمه‌های ساده گرفته تا فرم‌های پیچیده را شامل شوند.

چرا باید از کامپوننت Reusable در پروژه خود استفاده کنیم؟

همانطور که وب‌سایت ما رشد می‌کند و بزرگ‌تر می‌شود، می‌توانیم به راحتی ویژگی‌های جدید را با کامپوننت‌‌هایی که داریم ترکیب نموده و به پروژه اضافه کنیم. این کار باعث می‌شود تا کد ما مقیاس‌پذیرتر بوده و سازگارتر باشد.

همچنین می‌توانیم از کدهایی که قابلیت استفاده مجدد دارند، بدون اینکه نیاز باشدآن‌ها را دوباره از ابتدا بنویسیم در پروژه‌های آینده مورد استفاده قرار دهیم.

نحوه ساخت کامپوننت Reusable در React

دو نکته مهم وجود دارد که هنگام ساخت کامپوننت reusable در React باید به آن‌ها توجه کنیم:

اجتناب از Side Effectها

ما نباید منطقی که با داده‌های خارجی، مانند برقراری API callها در تعامل است را مستقیماً در یک کامپوننت reusable قرار دهیم. در عوض، می‌توانیم این منطق را به عنوان props به کامپوننت منتقل کنیم.

به عنوان مثال، اگر یک دکمه‌ای داریم که علاوه بر زیبایی بصری، کارهایی مانند دریافت داده از اینترنت را انجام دهد، ممکن است قابلیت استفاده مجدد را نداشته باشد.

کدی که در ادامه داریم یک کامپوننت button با قابلیت استفاده مجدد را نشان می‌دهد، اما فاقد بهترین شیوه می‌باشد. دلیل آن را در بخش مثال بررسی خواهیم کرد:

// This is a reusable button component (bad practice!)
const Button = () => {
  return (
    <button> Click Me </button>
  );
}

استفاده از Props

Props آرگومان‌هایی هستند که ما آن‌ها را برای سفارشی کردن رفتار و ظاهر یک کامپوننت به آن ارسال می‌کنیم. Props به ما این امکان را می‌دهد از یک کامپوننت برای اهداف مختلف استفاده نماییم.

// This is a button component that can change its color
const Button = ({ color }) => {
  return (
    <button style={{ backgroundColor: color }}> Click Here </button>
  );
}

این کد هنوز هم بهینه نیست زیرا ما یک برچسب ثابت به نام Click Here داریم. یعنی اگر بخواهیم متن روی دکمه را به Sign Up تغییر دهیم، باید به کامپوننت button برگردیم و تغییرات را رو آن اعمال کنیم. این بدان معناست هر بار که می‌خواهیم از متن دیگری استفاده کنیم، باید به عقب برگردیم و کد را ویرایش نماییم. به عبارت دیگر، این کامپوننت قابل استفاده مجدد نیست.

نحوه برطرف کردن این مشکل را در بخش بعدی بررسی می‌کنیم.

مثال‌هایی از کامپوننت‌های Reusable در React

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

Buttons

دکمه‌های بیسیک با استایل‌ها و عملکردهای مختلف.

// Button component
import React from "react";

const Button = ({ color, label, onClick }) => {
  return (
    <button
      className={`padding-2 shadow-none hover:shadow background-light-${color} hover:background-dark-${color}`}
      onClick={onClick}
    >
      {label}
    </button>
  );
};

export default Button;

// Using the Button component
<Button color="blue" label="Click Here" onClick={() => console.log("Button clicked!")} />

همانطور که می‌بینیم، ما در کامپوننت button متن Click Here را نداریم. قصد داریم دکمه‌ای که داریم قابلیت استفاده مجدد را داشته باشد، بنابراین چیزی در مورد استایل‌ها یا متن‌های سفارشی نمی‌داند. به این ترتیب، آن‌ها را به عنوان props، یعنی color، label و onClick ارسال می‌کنیم تا در آینده بدون ایجاد تغییر در کامپوننت اصلی button، آن‌ها را تغییر دهیم.

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

Navbars

Navigation barهایی که navigation ثابتی را در وب‌سایت ما ارائه می‌دهند.

// Navbar component
import React from "react";

const Navbar = ({ isLoggedIn }) => {
  return (
    <div className="navbar">
      <div className="navbar-container">
        <div className="navbar-logo">
          <img src={logo} alt="logo" />
        </div>
        <div className="navbar-links">
          <a href="/">Home</a>
          <a href="/about">About</a>
          <a href="/contact">Contact</a>
          {isLoggedIn ? (
            <a href="/profile">Profile</a>
          ) : (
            <a href="/login">Login</a>
          )}
        </div>
      </div>
    </div>
  );
};

export default Navbar;

// Using the Navbar component
<Navbar isLoggedIn={true} />

همانطور که در کد می‌بینیم، <Navbar isLoggedIn={true} /> را ارسال می‌کنیم.

این خط، از کامپوننت Navbar استفاده کرده و prop isLoggedIn را با مقدار true ارسال می‌کند، که نشان می‌دهد کاربر وارد شده است. در نتیجه لینک Profile را نمایش می‌دهد و لینک Login را پنهان می‌کند.

چرا استفاده از API Callها در کامپوننت Button بهینه نیست؟

اکنون همه چیز را در مورد کامپوننت reusable در React می‌دانیم. قصد داریم تا با حل یک مشکل پیچیده، کمی در این موضوع عمیق‌تر شویم.

سناریویی را در نظر می‌گیریم که در آن دکمه‌ای داریم که API call را انجام می‌دهد. کد کامپوننت button می‌تواند به صورت زیر باشد:

import React from "react"; 
import doAPICall from "../api"

const SaveButton  = () => {
  return (
    <button
      onClick={() => {
        doAPICall();
      }}
    >
      Save
    </button>
  );
}

export default SaveButton

کاملاً واضح است که نمی‌توانیم از دکمه بالا در مکان‌های مختلف مجددا استفاده کنیم زیرا این کامپوننت، یک side-effect به نام doAPICall() در داخل خود دارد.

می‌توانیم این کامپوننت را reusable کنیم. ابتدا باید side-effect را extract کنیم و آن را به عنوان یک prop به کامپوننت button مانند زیر منتقل نماییم:

const App = () =>  {
  function doAPICall() {
    // Does an API call to save the current state of the app.
  }

  return (
    <div>
      <SaveButton onClick={doAPICall}/>
    </div>
  )
}

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

const SaveButton  = ({
  onClick
}) => {
  return (
    <button
      onClick={onClick}
    >
      Save
    </button>
  );
}

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

const App = () =>  {
  function saveUser() {
    // Does an API call to save the user.
  }

  function saveProject() {
    // Does an API call to save the project.
  }

  return (
    <div>
      <SaveButton onClick={saveUser}/>
      <SaveButton onClick={saveProject}/>
    </div>
  )
}

همچنین می‌توانیم با استفاده از یک porp برای کنترل label، قابلیت reusable بودن کامپوننت button را بیشتر کنیم:

const App = () =>  {
  function saveUser() {
    // Does an API call to save the user.
  }

  function saveProject() {
    // Does an API call to save the project.
  }

  return (
    <div>
      <SaveButton onClick={saveUser} label="Save user"  />
      <SaveButton onClick={saveProject} label="Save project" />
    </div>
  )
}

حال کامپوننت button باید به شکل زیر باشد:

const SaveButton  = ({
  onClick,
  label
}) => {
  return (
    <button
      onClick={onClick}
    >
      {label}
    </button>
  );
}

جمع‌بندی

در این مقاله سعی کردیم تا با نحوه ساخت کامپوننت‌های React با قابلیت استفاده مجدد آشنا شویم.

باید این موضوع را به خاطر داشته باشیم، کامپوننت‌های reusable بلاک‌های سازنده توسعه قوی React هستند. با تمرین این کامپوننت‌ها می‌توانیم برنامه‌های React تمیزتر، کارآمدتر با قابلیت نگه‌داری بالاتر بسازیم.