نوشتن HOC در React  به صورت Functional Component مثلا connect توی redux

تایتل خیلی طولانی شد . نه؟ چون مفهوم HOC هنوز به عنوان یک عبارت قابل جستجو ، جا نیفتاده . میخوام ببینیم که چجوری میشه یک فانکشن نوشت شبیه به connect توی redux که زمان اکسپورت کردن کامپوننت ، داخل اون تابع این اتفاق بیفته . تمام عبارتی که بالا گفتم رو بهش میگن HOC یا High-order-Component . همونطور که میدونیم ، جاوا اسکریپت از بهترین زبان های Functional base موجوده . توابع نمیتونن مثل اشیاء ، اولویت داشته باشن . برای مثال شما میتونید داخل جاوا ، اولیت یک کلاس رو به یک کلاس دیگه با استفاده از extends و implement مشخص کنین . مثلا کلاس hello از کلاس HelloBase ارث میبره پس HelloBase اولویت بالاتری داره و از توابع میشه استفاده کرد . خوب این مثال داخل جاوا اسکریپت از صفر شدنی نیست . مگر اینکه از es6 استفاده کنیم و مفهوم class که یک مفهوم "Syntactical Sugar " هست . Classes are in fact "special functions", and just as you can define function expressions and function declarations, the class syntax has two components: class expressions and class declarations.خوب برای اینکه بتونیم این مفاهیم رو داشته باشیم ، از high-order-functions استفاده میکنیم و میتونیم مفاهیم ارث بری رو پیاده کنیم . داخل ری اکت به علت component base بودن ، مفهوم high-order-component یا HOC داریم . من یک مدل خیلی راحت رو پیاده سازی کردم که از سمپل cra هست . خوب فرض کنید که من یک کامپوننت دارم و میخوام تا زمانی که props ها موجود نیستند ، به من Loading... نمایش بده و وقتی props اومد ، محتویات کامپوننت . چیز پیچیده ای نیست . اما مین میخوام که Loading رو به شکل یک HOC بنویسم . اول از همه App.js رو به شکل زیر مینویسم . import React, {Component} from 'react'; import './App.css'; import Head from "./Head"; const App = () => { return ( <div className="App"> <Head hello={"Do it Now"}/> </div> ); } export default App; حالا یک نگاه میندازم به Head . کامپوننت Head چیز خاصی نیست . تا الان اصلا کار پیچیده ای نکردم . import React from "react"; import logo from "./logo.svg"; const Header=(props)=>{ return ( <header className="App-header"> {props.hello} <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> ) } export default Header;خوب الان که پروژه اجرا بشه همه چیز سر جاشه . اما من میخوام یک ثانیه بهم Loading رو نمایش بده و بعدش کاپوننت اجرا بشه . خوب میام داخل پوشه HOC یک فایل به اسم Loading میسازم . import React,{useState,useEffect} from "react" export const Loading = WrappedComponent => { return (props) => { const [hello,setHello]=useState(""); useEffect(()=>{ setTimeout(()=>{ setHello(props.hello) },1000) }) return(hello ? <WrappedComponent {...props}/> : <div>Loading...</div>) } }داخل ایت فایل ( که خیلی شبیه به یک کامپوننت نوشته شده ) ابتدا ایمپورت ها رو آوردم و یک state رو اماده کردم که کار کنه . باید بگم اگر hello مقدار داشت ، WrappedComponent رو نمایش بده . WrappedComponent در واقع میشه کامپوننتی که داخل HOC ما قرار هست که بیاد . همونطور که بالاتر گفتم HOC یک کامپوننت رو به عنوان آرگومان میگیره و روی اون تصمیم میگیره و کار رو جلو میبره . برای همینه که تابع connect داخل ریداکس ، مهمترین تابع هست . چون تمام state ها رو اونجا هندل میکنه و بالاترین سطح رو داره . یا تابع withStyle داخل کامپوننت material-ui . برای اینکه یک ثانیه من درست بشه و فکر کنم دارم async کار میکنم ، اومدم داخل useEffect یک setTimeout قرار دادم و گفتم بعد از یک ثانیه state رو تغییر بده و hello رو پر کن . با چی؟ با props ه داخل کامپوننت تعریف شده . خوب همه چیز ظاهرا خوبه . اما چجوری استفده کنیم؟ یک تغییر کوچیک داخل Head.js باید بدیم . به شکل زیر :import React from "react"; import logo from "./logo.svg"; import {Loading} from "./HOC/Loading"; const Header=(props)=>{ return ( <header className="App-header"> {props.hello} <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> ) } export default Loading(Header);Loading رو ایمپورت کردم و انتهای کامپوننت Header رو wrapped کردم داخل Loading . حالا اجرا کنین و میبینین که یک ثانیه ، Loading... رو میبینید رو بعدش کامپوننت رو . این کار فوایدش خیلی زیاده . برای مثال شما با context api میخواین تمام استیت ها رو منیج کنین و روی هر تغییر تصمیمگیری کنین ( مثل سبد خرید فروشگاه ) . میتونید یک HOC به اسم shop بنویسید و تمام . همه چیز راحت قابل هندل کردنه .