این مقاله توسط نویسنده مهمان ارائه شده است جک فرانکلین. پست های مهمان SitePoint قصد دارند محتوای جذاب نویسندگان و سخنرانان برجسته جامعه JavaScript را برای شما به ارمغان بیاورند

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

توابع خالص

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

  • تمام داده هایی که با آنها سروکار دارد به عنوان استدلال اعلام می شود
  • داده های داده شده یا داده های دیگر را تغییر نمی دهد (که اغلب به این موارد گفته می شود اثرات جانبی)
  • با توجه به ورودی یکسان ، همیشه همان خروجی را برگردانید.

به عنوان مثال add عملکرد زیر خالص است:

function add(x, y) {
  return x + y;
}

با این حال ، عملکرد badAdd در زیر نجس است:

let y = 2;
function badAdd(x) {
  return x + y;
}

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

let y = 2;
badAdd(3) 
y = 3;
badAdd(3) 

برای مطالعه بیشتر در مورد توابع خالص می توانید “مقدمه ای بر برنامه نویسی منطقی خالص”توسط مارک براون.

در حالی که توابع خالص بسیار مفید هستند و اشکال زدایی و آزمایش یک برنامه را بسیار آسان می کنند ، گاهی اوقات شما نیاز به ایجاد توابع ناخالصی دارید که دارای عوارض جانبی هستند ، یا عملکرد عملکرد فعلی را که قادر به دسترسی مستقیم آن نیستید اصلاح کنید (یک عملکرد از کتابخانه ، به عنوان مثال). برای فعال کردن این ، ما باید توابع مرتبه بالاتر را بررسی کنیم.

توابع با مرتبه بالاتر

تابع مرتبه بالاتر تابعی است که وقتی فراخوانی می شود تابع دیگری را برمی گرداند. غالباً آنها نیز تابعی را به عنوان آرگومان در نظر می گیرند ، اما برای اینكه تابعی مرتبه بالاتر در نظر گرفته شود ، این مورد لازم نیست.

بگذارید بگوییم ما خودمان را داریم add عملکرد از بالا ، و ما می خواهیم برخی از کدها را بنویسیم تا هنگامی که آن را صدا می کنیم ، نتیجه را قبل از بازگرداندن نتیجه به کنسول وارد کنیم. ما قادر به ویرایش نیستیم add تابع ، بنابراین در عوض می توانیم یک تابع جدید ایجاد کنیم:

function addAndLog(x, y) {
  const result = add(x, y);
  console.log(`Result: ${result}`);
  return result;
}

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

function logAndReturn(func) {
  return function(...args) {
    const result = func(...args)
    console.log('Result', result);
    return result;
  }
}

اکنون می توانیم از این تابع استفاده کرده و از آن برای اضافه کردن logging به آن استفاده کنیم add و subtract:

const addAndLog = logAndReturn(add);
addAndLog(4, 4) 

const subtractAndLog = logAndReturn(subtract);
subtractAndLog(4, 3) 

logAndReturn یک تابع مرتبه بالاتر است زیرا تابعی را به عنوان آرگومان خود در نظر می گیرد و یک تابع جدید را برمی گرداند که می توانیم آن را فراخوانی کنیم. این موارد برای بسته بندی عملکردهای موجود که نمی توانید در رفتار تغییر دهید بسیار مفید هستند. برای اطلاعات بیشتر در این باره ، مقاله M. David Green را بررسی کنید “توابع مرتبه بالاتر در JavaScript“، که جزئیات بسیار بیشتری در مورد موضوع ارائه می دهد.

قلم را ببینید
توابع سفارش بالاتر
توسط SitePoint (SitePoint)
بر CodePen.

اجزای مرتبه بالاتر

با رفتن به React land ، می توانیم از همان منطق بالا استفاده کنیم تا م componentsلفه های موجود React را بگیریم و رفتارهای اضافی به آنها بدهیم.

توجه: با مقدمه واکنش به قلاب ها، در React 16.8 منتشر شد ، توابع مرتبه بالاتر کمی مفیدتر می شوند زیرا قلاب ها بدون نیاز به اجزای اضافی اشتراک رفتار را فعال می کنند. همانطور که گفته شد ، آنها هنوز هم یک ابزار مفید برای استفاده در کمربند شما هستند.

در این بخش ، ما می خواهیم استفاده کنیم React Router، راه حل مسیریابی واقعی برای React. اگر می خواهید با کتابخانه شروع کنید ، من بسیار توصیه می کنم مستندات روتر را واکنش نشان دهید به عنوان بهترین مکان برای شروع

React Router’s Link

React Router فراهم می کند <NavLink> م componentلفه ای که برای ارتباط بین صفحات در یک برنامه React استفاده می شود. یکی از خواص این است <NavLink> جز component می گیرد است activeClassName. وقتی یک <NavLink> این ویژگی را دارد و در حال حاضر فعال است (کاربر در URL است که پیوند به آن اشاره دارد) ، به این جز component این کلاس داده می شود و توسعه دهنده را قادر می سازد آن را سبک کند.

این یک ویژگی واقعاً مفید است و در برنامه فرضی ما تصمیم می گیریم که همیشه می خواهیم از این ویژگی استفاده کنیم. با این حال ، پس از انجام این کار به سرعت متوجه می شویم که این امر همه ما را ساخته است <NavLink> م componentsلفه های بسیار شفاف:

<NavLink to="/" activeClassName="active-link">Home</NavLink>
<NavLink to="/about" activeClassName="active-link">About</NavLink>
<NavLink to="/contact" activeClassName="active-link">Contact</NavLink>

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

در عوض ، ما می توانیم یک م componentلفه بنویسیم که <NavLink> جزء:

const AppLink = (props) => {
  return (
    <NavLink to={props.to} activeClassName="active-link">
      {props.children}
    </NavLink>
  );
};

و اکنون می توانیم از این جز component استفاده کنیم که پیوندهای ما را مرتب می کند:

<AppLink to="/home" exact>Home</AppLink>
<AppLink to="/about">About</AppLink>
<AppLink to="/contact">Contact</AppLink>

در اکوسیستم React ، این اجزا به عنوان اجزای مرتبه بالاتر شناخته می شوند ، زیرا آنها یک م componentلفه موجود را می گیرند و کمی آن را دستکاری می کنند بدون تغییر در م existingلفه موجود. همچنین می توانید این موارد را به عنوان اجزای لفافی در نظر بگیرید ، اما معمولاً در محتوای مبتنی بر React به آنها اجزای مرتبه بالاتر گفته می شود.

اجزای مرتبه بالاتر بهتر

م aboveلفه فوق م worksثر است ، اما ما می توانیم خیلی بهتر عمل کنیم. <AppLink> م componentلفه ای که ایجاد کردیم برای هدف کاملاً مناسب نیست.

پذیرش چندین ویژگی

<AppLink> جز component انتظار دو ویژگی دارد:

  • this.props.to، URL که پیوند باید کاربر را به آن ببرد
  • this.props.children، که متن نمایش داده شده به کاربر است

با این حال <NavLink> کامپوننت خصوصیات بیشتری را می پذیرد و ممکن است زمانی باشد که بخواهید خصوصیات اضافی را بهمراه دو مورد فوق منتقل کنید ، که تقریباً همیشه می خواهیم آنها را تصویب کنیم. ما ساخته نشده است <AppLink> با کدگذاری دقیق خواص مورد نیاز بسیار قابل توسعه است.

گسترش JSX

JSX ، نحوی مانند HTML که ما برای تعریف عناصر React استفاده می کنیم ، از آن پشتیبانی می کند اپراتور گسترش برای انتقال یک شی به یک جز component به عنوان ویژگی. به عنوان مثال ، نمونه های کد زیر به همان چیز دست می یابند:

const props = { a: 1, b: 2};
<Foo a={props.a} b={props.b} />

<Foo {...props} />

استفاده كردن {...props} هر کلید را در جسم پخش کرده و به آن منتقل می کند Foo به عنوان یک دارایی فردی.

ما می توانیم با استفاده از این ترفند استفاده کنیم <AppLink> بنابراین ما از هرگونه مالکیت خودسرانه پشتیبانی می کنیم <NavLink> پشتیبانی می کند. با این کار ما در آینده نیز خود را اثبات می کنیم. اگر <NavLink> ویژگی های جدیدی را در آینده اضافه می کند که اجزای بسته بندی ما از آنها پشتیبانی می کند.

const AppLink = (props) => {
  return <NavLink {...props} activeClassName="active-link" />;
}

اکنون <AppLink> هرگونه ویژگی را قبول می کند و از آنها عبور می کند. توجه داشته باشید که ما همچنین می توانیم به جای ارجاع صریح از فرم خود بسته شونده استفاده کنیم {props.children} در بین <NavLink> برچسب ها واکنش نشان می دهد children به عنوان یک پایه منظم یا به عنوان عناصر کودک از یک جز between بین برچسب باز و بسته عبور داده شود.

سفارش ملک در React

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

<AppLink to="/special-link" activeClassName="special-active">Special Secret Link</AppLink>

با این حال ، این کار نمی کند. دلیل آن به ترتیب ترتیب خواص است که ما رندر را ارائه می دهیم <NavLink> جزء:

return <Link {...props} activeClassName="active-link" />;

هنگامی که در یک مولفه React چندین بار ویژگی مشابه دارید ، آخرین اعلامیه برنده است. این یعنی آخرین ما activeClassName="active-link" اعلامیه همیشه برنده خواهد شد ، زیرا قرار داده شده است بعد از {...this.props}. برای رفع این مشکل ، می توانیم خصوصیات را دوباره مرتب کنیم تا گسترش یابیم this.props آخر. این به این معنی است که پیش فرض های معقولی را تنظیم می کنیم که دوست داریم از آنها استفاده کنیم ، اما اگر کاربر واقعاً نیاز داشته باشد می تواند آنها را نادیده بگیرد:

return <Link activeClassName="active-link" {...props}  />;

با ایجاد م componentsلفه های مرتبه بالاتر که اجزای موجود را می پوشاند اما با رفتارهای اضافی ، ما پایگاه کد خود را تمیز نگه می داریم و با تکرار نکردن خصوصیات و نگه داشتن مقادیر آنها فقط در یک مکان ، از تغییرات آینده دفاع می کنیم.

سازندگان تراز بالاتر

غالباً شما تعدادی م componentsلفه خواهید داشت که باید با همان رفتار بسته بندی کنید. این بسیار مشابه موارد قبلی است که در این مقاله بسته بندی کردیم add و subtract برای اضافه کردن گزارش به آنها.

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

راه حل این مسئله ایجاد تابعی است که بتوانیم با یک م Reلفه React فراخوانی کنیم. سپس تابع یک کامپوننت جدید React را برمی گرداند که م givenلفه داده شده را رندر می کند اما دارای ویژگی اضافی است که به آن امکان دسترسی به اطلاعات کاربر را می دهد.

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

function wrapWithUser(Component) {
  
  const secretUserInfo = {
    name: 'Jack Franklin',
    favouriteColour: 'blue'
  };

  
  
  return function(props) {
    
    
    return <Component user={secretUserInfo} {...props} />
  }
}

این تابع یک م componentلفه React می گیرد (که با توجه به م componentsلفه های React در ابتدا باید با حروف بزرگ مشخص شود) و یک تابع جدید را برمی گرداند که م theلفه ای را که به آن داده شده است با ویژگی اضافی ارائه می دهد. user، که روی secretUserInfo.

حالا بیایید یک ملفه را بگیریم ، <AppHeader>، که می خواهد به این اطلاعات دسترسی پیدا کند تا بتواند کاربر وارد شده را نمایش دهد:

const AppHeader = function(props) {
  if (props.user) {
    return <p>Logged in as {props.user.name}</p>;
  } else {
    return <p>You need to login</p>;
  }
}

مرحله آخر اتصال این جز component به بالا است بنابراین داده می شود this.props.user. ما می توانیم با انتقال این م componentلفه به م componentلفه جدیدی ایجاد کنیم wrapWithUser تابع:

const ConnectedAppHeader = wrapWithUser(AppHeader);

ما اکنون یک <ConnectedAppHeader> م componentلفه ای که می تواند ارائه شود و به آن دسترسی خواهد داشت user هدف – شی.

من انتخاب کردم که جز the را صدا کنم ConnectedAppHeader زیرا فکر می کنم آن را به عنوان داده های اضافی متصل کرده ام که به همه م componentلفه ها دسترسی ندارند.

این الگو در کتابخانه های React ، به ویژه در ، بسیار رایج است ردوکس، بنابراین آگاهی از نحوه کارکرد آن و دلایل استفاده از آن به شما کمک می کند تا برنامه شما رشد کرده و به کتابخانه های شخص ثالث دیگری که از این روش استفاده می کنند اعتماد کنید.

نتیجه

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

با ایجاد م componentsلفه های مرتبه بالاتر ، می توانید داده ها را فقط در یک مکان مشخص نگه دارید و بازسازی مجدد را آسان تر کنید. سازندگان عملکرد با مرتبه بالاتر این امکان را برای شما فراهم می کنند که اکثر داده ها را خصوصی نگه دارید و فقط داده هایی را در معرض اجزای واقعاً مورد نیاز قرار دهید. با این کار مشخص می کنید که چه م componentsلفه هایی از کدام بیت داده استفاده می کنند و با رشد برنامه شما این امر را مفید می دانید.

اگر سوالی دارید ، دوست دارم آنها را بشنوم. خیال راحتم کن Jack_Franklin در توییتر.