۵ روش برای طراحی ساده قلاب React | راهنمای کاربردی
زمانی که یک قلاب سفارشی را مینویسیم، در اغلب موارد در نهایت یک راهکار بسیار پیچیده به دست میآید. این مسئله در پارهای موارد میتواند موجب رفتار غیر عادی و رندرهای مجدد فاقد کاربرد و یا تولید کدی با قابلیت نگهداری پایین شود. در این مقاله 5 روش برای طراحی ساده قلاب React را مطرح میکنیم.
کاهش تعداد useState
زمانی که مشغول توسعه قلابها هستیم، گاهی اوقات یا فراخوانیهای زیاد useState به دست میآید یا کل حالت به یک useState منفرد بسیار پیچیده کاهش مییابد. یکی از بهترین روشها برای افزایش خوانایی قلاب این است که به فراخوانیهای useState اولویت بدهیم. برای پیادهسازی حالت در قلابها باید چند قاعده را رعایت کنیم که در ادامه توضیح داده شدهاند.
اولویت دادن به خوانایی
بهتر است حالت را به صورت یک شیء بخوانیم تا این که از چند دستور useState با مقادیر ساده استفاده کنیم. دستورهای کمتر useState همچنین موجب میشود که بازگشت قلاب آسانتر باشد و پیادهسازی نیز به روش سرراستتری انجام میپذیرد. شاید این موضوع مورد ترجیح شما نباشد، اما به باور بسیاری از توسعهدهندگان در زمان نوشتن کد، مهمترین چیز خوانایی کد است. با رعایت این قاعده، نگهداری کد شما آسانتر میشود، مجبور میشوید در مورد آن چه مینویسید فکر کنید و به این ترتیب کاری میکنید که پیگیری کد برای همکاران آسانتر شود. این مهمترین نکتهای است که در سراسر این مقاله مورد اشاره قرار میگیرد.
ارزیابی محتوای شیئ حالت
یک کامپوننت هرگز از ابتدا به صورت دقیقی برنامهنویسی نمیشود. زمانی که یک کامپوننت رشد میکند، مشخصههایی که در useState نگهداری میشوند نیز به تدریج پیچیدهتر میشوند. در سراسر چرخه توسعه، همواره بهتر است محتوای فراخوانیهای useState را بررسی کنید تا مشخص شود آیا جداسازی بخشهای حالت در فراخوانیهای اضافی useState کار مناسبی است یا نه. شاید بهتر باشد مقادیر حالت را از طریق تابع یا نوع گروهبندی کنید. به طور کلی بهتر است دادههای حالت بر اساس مشخصهای که با توالی بیشتری بهروز میشود یا بر اساس مشخصههای حالت یا تابع مانند مشخصههای داده و view گروهبندی شوند.
از مزیت بازگشتی قلاب بهره بگیرید
زمانی که تازه شروع به نوشتن قلابهای سفارشی کردهاید، غالباً از سبک بازگشتی شبیه به قلاب پیشفرض useState استفاده میکنید. با این که این رویکرد بدی نیست، اما استفاده از یک آرایه بازگشتی برای بازگشت دادن چند متغیر حالت بر مبنای تابعها میتواند کار پیچیدهای باشد. قلابی را تصور کنید که دو متغیر حالت متمایز را که یکی برای داده و دیگری برای حالت نما است بازگشت میدهد و علاوه بر آن تابعهایی برای مدیریت انتخاب دادهها، به سبک بازگشتی آرایهای نوشته شده است. این قلاب باید چیزی مانند زیر باشد:
1function useBasicHook() {
2 const [dataState, setDataState] = useState({
3 serverData: {},
4 selections: {}
5 });
6 const [viewState, setViewState] = useState({
7 menuExpanded: false,
8 submitFormData: {}
9 })
10
11 const toggleMenuExpand = () => {
12 setViewState({
13 menuExpanded: !viewState.menuExpanded,
14 submitFormData: viewState.submitFormData
15 })
16 }
17
18 return [dataState, viewState, toggleMenuExpande];
19}
20
21function BasicComponent(){
22 const [dataState, viewState, toggleMenuExpand] = useBasicHook();
23
24 return <div>
25 </div>
26}
با نگاه کردن به این قلاب به سادگی میبینید که وقتی تابعها یا متغیرهای دیگری به مقدار بازگشتی اضافه شوند، پیادهسازی قلاب میتواند به سرعت از کنترل خارج شود. اگر عادت به باز کردن آرایه خارج از ترتیب یا استفاده از نامهای نامناسب داشته باشید، این امر موجب ایجاد سردرگمی اضافی و خطاهای احتمالی میشود. با بهروزرسانی قلاب برای بازگشت یک شیء مانند زیر میتوانیم از بسیاری از این موارد جلوگیری کنیم:
1function useBasicHook() {
2 const [dataState, setDataState] = useState({
3 serverData: {},
4 selections: {}
5 });
6 const [viewState, setViewState] = useState({
7 menuExpanded: false,
8 submitFormData: {}
9 })
10
11 const toggleMenuExpand = () => {
12 setViewState({
13 menuExpanded: !viewState.menuExpanded,
14 submitFormData: viewState.submitFormData
15 })
16 }
17
18 return {
19 dataState: dataState,
20 viewState: viewState,
21 toggleMenuExpand: toggleMenuExpand
22 };
23}
24
25function BasicComponent(){
26 const state = useBasicHook();
27 // or
28 // const {dataState, viewState, toggleMenuExpand} = useBasicHook();
29
30 return <div>
31 </div>
32}
تبدیل این مقدار بازگشت به یک شیء مزیتهای دیگری نیز دارد که شامل موارد زیر است:
- در صورتی که قلاب در میان چند کامپوننت مشترک است یا به صورت یک کتابخانه استفاده میشود، موجب بهبود سازگاری نسخه قلاب پس از بهروزرسانی میشود.
- همچنین میتوانید شیء را در زمان استفاده از قلاب باز کنید و سطحی از خوانایی API قلاب را بر مبنای یک کامپوننت داشته باشید.
یک نکته جالب دیگر که میتوان با مقدار بازگشتی قلاب انجام داد، ایجاد تابعهای فکتوری کامپوننت کوچک بر مبنای حالت و درون حالت است. به این ترتیب روش خوبی برای اشتراک یک متد سازنده کامپوننت با کامپوننتی که قلاب را پیادهسازی میکند خواهیم داشت و در این مسیر نیازی هم به افشای حالت با آن کامپوننت نداریم.
ساده کردن فراخوانی setState با یک قلاب Merge
توسعه کد ریاکت با استفاده از کامپوننتهای مبتنی بر کلاس به کامپوننتهای تابعی برخی مزیتهای حاضر و آماده در زمینه مدیریت حالت دارد که مهمترین آنها قابلیت ادغام حالت قدیمی با حالت جدید است. مستندات ریاکت در مورد حالت (+) نمونههای خوبی از ظرفیتهای داخلی React.Component برای ادغام حالت معرفی کردهاند.
با این که این کارکرد مستقیماً در داخل قلابها تعبیه نشده است، اما میتوانیم این رفتار را با ساخت یک قلاب سفارشی شبیهسازی کنیم که در آن با جایگزینی فراخوانیهای useState، رفتار مشابهی به دست میآید:
1function useDataHook() {
2 const [dataState, setDataState] = useState({
3 serverData: {},
4 selections: {}
5 });
6
7 return dataState;
8}
9
10function useDisplayHook() {
11 const [viewState, setViewState] = useState({
12 menuExpanded: false,
13 submitFormData: {}
14 })
15
16 const toggleMenuExpand = () => {
17 setViewState({
18 menuExpanded: !viewState.menuExpanded,
19 submitFormData: viewState.submitFormData
20 })
21 }
22
23 return {
24 viewState: viewState,
25 toggleMenuExpand: toggleMenuExpand
26}
27
28function BasicComponent(){
29 const data = useDataHook();
30 const display = useDisplayHook();
31
32 return <div>
33 </div>
34}
از افراز قلاب استفاده کنید
علیرغم پیچیدگیهای کامپوننت، همواره بهتر است از قلابهای سفارشی استفاده کنیم، اما در زمان ساخت یک قلاب سفارشی، همواره خوب است که یک قلاب بسیار پیچیده را به چند قلاب کوچکتر و سادهتر افراز کنیم. به طور معمول منطق قلاب بر اساس تابع افراز میشود. برای نمونه میتوان یک قلاب را به زیرمجموعههای منطقی تقسیم کرد، به طوری که یک قلاب به تعامل داده/API وب و قلاب دیگر به نمایش حالت اختصاص یابد. اگر مثال بخش قبلی در مورد بازگشتی قلاب را مورد بررسی قرار دهیم، میبینیم که بهتر است آن را به صورت زیر افراز کنیم:
1function useMergeState(initialState) {
2 const [state, setState] = useState(initialState);
3 // use useRef to improve functionality when calling the setState asynchronously
4 const stateRef = useRef(state);
5
6 function setRefState(newState) {
7 stateRef.current = newState;
8 return setState(newState);
9 }
10
11 function mergeState(newState) {
12 var finalState = newState;
13 /**
14 * Determine if the state data types match, if so continue the merge,
15 * if not, throw a console warning and overwrite with new state
16 */
17 if (typeof stateRef.current !== typeof newState) {
18 console.warn(
19 "useMergeState warning: state data types do not match, overwriting state with new state"
20 );
21 finalState = newState;
22 } else {
23 /**
24 * process the state merge here
25 */
26 if (typeof stateRef.current == "object" && !Array.isArray(stateRef.current)) {
27 // existing state is an object, go ahead and attempt merge
28 if (typeof newState == "object" && !Array.isArray(newState)) {
29 finalState = { ...stateRef.current, ...newState };
30 }
31 }
32 }
33
34 return setRefState(finalState);
35 }
36
37 return [stateRef.current, mergeState];
38}
ارزیابی فراخوانیهای useEffect برای جلوگیری از رندرهای مجدد غیر ضروری
قلاب useEffect به طرز خارقالعادهای مفید است، اما در صورتی که به طرز نادرستی استفاده شود، ممکن است منجر به رندرهای مجدد زیادی شود. زمانی که به قلاب سفارشی خود نگاه میکنید، بهتر است فراخوانیهای useEffect را ارزیابی کنید. به این منظور از قواعد سرراست زیر استفاده میشود:
- اگر یک useEffect به یک متغیر حالت در همان دامنه قلاب گوش میدهد، آن افکت خودش هرگز نمیتواند حالت را بهروزرسانی کند.
- اگر چند گزاره useEffect دارید که به مجموعه یکسانی از متغیرها گوش میدهند، میتوانید آنها را ترکیب کنید.
- با این که ترکیب کردن گزارههای useEffect میتواند برای کاهش تعداد رندرهای مجدد مفید باشد، اما همیشه این خوانایی کد است که در اولویت قرار دارد.
سخن پایانی
در این مقاله فهرست مختصری از مواردی که به ساده کردن فرایند ساخت قلابها و کامپوننتهای ری اکت کمک میکنند را ارائه کردیم. امیدواریم این راهنما به شما کمک کند تا کامپوننتهای ریاکت را به طرز بهتری ایجاد کنید و موجب ارتقای سطح دانش شما در این خصوص شده باشد. در خصوص این موارد نیز مانند هر موضوع دیگری در برنامهنویسی، روشهای بیشماری برای انجام کار وجود دارد، اما امیدواریم 5 موردی که در این مقاله ارائه شدند، به شما کمک کنند تا قلابهای خود را سادهتر طراحی کنید و به این ترتیب بتوانید کد تمیزتری بنویسید.