اگرچه React یکی از محبوب ترین و پرکاربردترین چارچوب های پیش فرض در جهان است ، اما بسیاری از توسعه دهندگان هنوز در مورد تغییر شکل کد برای بهبود قابلیت استفاده مجدد تلاش می کنند. اگر تا به حال متوجه شده اید که یک تکه کد را در سراسر برنامه React خود تکرار می کنید ، به مقاله مناسب رسیده اید.
در این آموزش ، شما با سه شاخص متداول آشنا می شوید که زمان ساخت یک کامپوننت React قابل استفاده مجدد فرا رسیده است. سپس با ساختن یک طرح قابل استفاده مجدد و دو قلاب هیجان انگیز React ، به بررسی برخی از دموی عملی می پردازیم.
وقتی خواندن را به پایان برسانید ، می توانید خودتان تشخیص دهید چه زمانی ایجاد اجزای React قابل استفاده مجدد مناسب است و چگونه انجام این کار
این مقاله دانش اساسی در مورد قلاب های React و React را فرض می کند. اگر می خواهید در مورد این موضوعات صحبت کنید ، توصیه می کنم راهنمای “شروع به کار با React” و “Introduction to React Hooks” را مطالعه کنید.
سه شاخص برتر یک م Reلفه واکنش مجدد قابل استفاده مجدد
ابتدا اجازه دهید برخی از نشانه ها را بررسی کنیم چه زمانی شاید بخواهید این کار را انجام دهید
ایجاد تکرار بسته بندی با همان سبک CSS
نشانه مورد علاقه من در مورد زمان ایجاد یک جزء قابل استفاده مجدد ، استفاده مکرر از همان سبک CSS است. اکنون ، ممکن است فکر کنید ، “یک لحظه صبر کنید: چرا من به سادگی یک نام کلاس را به عناصری که دارای سبک CSS یکسانی هستند اختصاص نمی دهم؟” کاملا حق با شما است. ایده خوبی نیست که هر بار برخی از عناصر در اجزای مختلف دارای سبک مشابهی باشند ، اجزای قابل استفاده مجدد ایجاد شود. در واقع ، ممکن است پیچیدگی غیر ضروری را ایجاد کند. بنابراین باید یک چیز دیگر از خود بپرسید: آیا این عناصر دارای سبک معمول هستند بسته بندی؟
به عنوان مثال ، صفحات ورود و ثبت نام زیر را در نظر بگیرید:
import './common.css';
function Login() {
return (
<div className='wrapper'>
<main>
{...}
</main>
<footer className='footer'>
{...}
</footer>
</div>
);
}
import './common.css';
function Signup() {
return (
<div className='wrapper'>
<main>
{...}
</main>
<footer className='footer'>
{...}
</footer>
</div>
);
}
سبک های مشابهی در مورد ظرف (the <div>
element) و پاورقی هر جزء. بنابراین در این مورد ، می توانید دو جزء قابل استفاده مجدد ایجاد کنید – <Wrapper />
و <Footer />
– و از آنها برای حمایت از کودکان استفاده کنید. به عنوان مثال ، جزء ورود را می توان به صورت زیر تغییر شکل داد:
import Footer from "./Footer.js";
function Login() {
return (
<Wrapper main={{...}} footer={<Footer />} />
);
}
در نتیجه ، دیگر نیازی به واردات ندارید common.css
در چندین صفحه یا ایجاد یکسان <div>
عناصری برای پیچاندن همه چیز
استفاده مکرر از شنوندگان رویداد
برای پیوستن یک شنونده رویداد به یک عنصر ، می توانید آن را در داخل مدیریت کنید useEffect()
مثل این:
import { useEffect } from 'react';
function App() {
const handleKeydown = () => {
alert('key is pressed.');
}
useEffect(() => {
document.addEventListener('keydown', handleKeydown);
return () => {
document.removeEventListener('keydown', handleKeydown);
}
}, []);
return (...);
}
یا می توانید این کار را مستقیماً در داخل JSX خود انجام دهید ، همانطور که در جزء دکمه زیر نشان داده شده است:
function Button() {
return (
<button type="button" onClick={() => { alert('Hi!')}}>
Click me!
</button>
);
};
وقتی می خواهید یک شنونده رویداد را به آن اضافه کنید document
یا window
، شما باید از روش اول استفاده کنید. با این حال ، همانطور که ممکن است قبلاً متوجه شده باشید ، اولین روش نیاز به کد بیشتری با استفاده از useEffect()
، addEventListener()
و removeEventListener()
به بنابراین در چنین مواردی ، ایجاد یک قلاب سفارشی به اجزای شما اجازه می دهد تا مختصرتر باشند.
چهار سناریوی ممکن برای استفاده از شنوندگان رویداد وجود دارد:
- همان شنونده رویداد ، همان گرداننده رویداد
- شنونده رویداد یکسان ، کنترل کننده رویداد متفاوت
- شنونده رویداد متفاوت ، کنترل کننده رویداد یکسان
- شنونده رویداد متفاوت ، مدیریت رویداد متفاوت
در سناریوی اول ، می توانید یک قلاب ایجاد کنید که هم شنونده رویداد و هم مدیریت رویداد در آن تعریف شده باشد. قلاب زیر را در نظر بگیرید:
import { useEffect } from 'react';
export default function useKeydown() {
const handleKeydown = () => {
alert('key is pressed.');
}
useEffect(() => {
document.addEventListener('keydown', handleKeydown);
return () => {
document.removeEventListener('keydown', handleKeydown);
}
}, []);
};
سپس می توانید از این قلاب در هر جزء به شرح زیر استفاده کنید:
import useKeydown from './useKeydown.js';
function App() {
useKeydown();
return (...);
};
برای سه سناریوی دیگر ، توصیه می کنم قلابی ایجاد کنید که یک رویداد و عملکرد مدیریت رویداد را به عنوان لوازم جانبی دریافت کند. به عنوان مثال ، من عبور می کنم keydown
و handleKeydown
به عنوان لوازم جانبی برای قلاب سفارشی من قلاب زیر را در نظر بگیرید:
import { useEffect } from 'react';
export default function useEventListener({ event, handler} ) {
useEffect(() => {
document.addEventListener(event, props.handler);
return () => {
document.removeEventListener(event, props.handler);
}
}, []);
};
سپس می توانید از این قلاب در هر جزء به شرح زیر استفاده کنید:
import useEventListener from './useEventListener.js';
function App() {
const handleKeydown = () => {
alert('key is pressed.');
}
useEventListener('keydown', handleKeydown);
return (...);
};
استفاده مکرر از همان اسکریپت GraphQL
در مورد استفاده مجدد از کد GraphQL نیازی نیست به دنبال علائم باشید. برای برنامه های پیچیده ، اسکریپت های GraphQL برای یک پرس و جو یا جهش به راحتی 30 تا 50 خط کد را اشغال می کنند ، زیرا ویژگی های زیادی برای درخواست وجود دارد. اگر بیش از یک یا دو بار از یک اسکریپت GraphQL استفاده می کنید ، من فکر می کنم که سزاوار قلاب سفارشی خود است.
به مثال زیر توجه کنید:
import { gql, useQuery } from "@apollo/react-hooks";
const GET_POSTS = gql`
query getPosts {
getPosts {
user {
id
name
...
}
emojis {
id
...
}
...
}
`;
const { data, loading, error } = useQuery(GET_POSTS, {
fetchPolicy: "network-only"
});
به جای تکرار این کد در هر صفحه ای که از انتهای پست درخواست می کند ، باید یک قلاب React برای این API خاص ایجاد کنید:
import { gql, useQuery } from "@apollo/react-hooks";
function useGetPosts() {
const GET_POSTS = gql`{...}`;
const { data, loading, error } = useQuery(GET_POSTS, {
fetchPolicy: "network-only"
});
return [data];
}
const Test = () => {
const [data] = useGetPosts();
return (
<div>{data?.map(post => <h1>{post.text}</h1>)}</div>
);
};
ایجاد سه م Reلفه واکنش مجدد قابل استفاده مجدد
اکنون که برخی از علائم رایج را مشاهده کرده ایم چه زمانی برای ایجاد یک م componentلفه جدید که می توانید در سراسر برنامه واکنش خود به اشتراک بگذارید ، بیایید این دانش را در عمل به کار گیریم و سه نسخه نمایشی عملی بسازیم.
1. جزء طرح بندی
React معمولاً برای ایجاد برنامه های وب پیچیده استفاده می شود. این بدان معناست که تعداد زیادی صفحه باید در React توسعه داده شود و من شک دارم که هر صفحه از یک برنامه دارای طرح بندی متفاوتی باشد. به عنوان مثال ، یک برنامه وب متشکل از 30 صفحه معمولاً از کمتر از پنج طرح بندی مختلف استفاده می کند. بنابراین ، ایجاد یک طرح بندی انعطاف پذیر و قابل استفاده مجدد که بتواند در صفحات مختلف مورد استفاده قرار گیرد ضروری است. این باعث می شود خطوط زیادی از کد و در نتیجه زمان فوق العاده ای برای شما ذخیره شود.
جزء عملکردی React زیر را در نظر بگیرید:
import React from "react";
import style from "./Feed.module.css";
export default function Feed() {
return (
<div className={style.FeedContainer}>
<header className={style.FeedHeader}>Header</header>
<main className={style.FeedMain}>
{
<div className={style.ItemList}>
{itemData.map((item, idx) => (
<div key={idx} className={style.Item}>
{item}
</div>
))}
</div>
}
</main>
<footer className={style.FeedFooter}>Footer</footer>
</div>
);
}
const itemData = [1, 2, 3, 4, 5];
این یک صفحه وب معمولی است که دارای یک <header>
، آ <main>
و الف <footer>
به اگر 30 صفحه وب دیگر مانند این وجود داشته باشد ، به راحتی از نوشتن مکرر برچسب های HTML و اعمال یک سبک بارها و بارها خسته می شوید.
در عوض ، می توانید یک جزء طرح بندی ایجاد کنید که دریافت می کند <header>
، <main>
و <footer>
به عنوان لوازم جانبی ، مانند کد زیر:
import React from "react";
import style from "./Layout.module.css";
import PropTypes from "prop-types";
export default function Layout({ header, main, footer }) {
return (
<div className={style.Container}>
<header className={style.Header}>{header}</header>
<main className={style.Main}>{main}</main>
<footer className={style.Footer}>{footer}</footer>
</div>
);
}
Layout.propTypes = {
main: PropTypes.element.isRequired,
header: PropTypes.element,
footer: PropTypes.element
};
این جزء نیاز ندارد <header>
و <footer>
به بنابراین ، می توانید از این طرح بندی یکسان برای صفحات صرف نظر از اینکه دارای سرصفحه یا پاورقی باشند استفاده کنید.
با استفاده از این جزء طرح بندی ، می توانید صفحه خوراک خود را به یک بلوک کد پیچیده تر تبدیل کنید:
import React from "react";
import Layout from "./Layout";
import style from "./Feed.module.css";
export default function Feed() {
return (
<Layout
header={<div className={style.FeedHeader}>Header</div>}
main={
<div className={style.ItemList}>
{itemData.map((item, idx) => (
<div key={idx} className={style.Item}>
{item}
</div>
))}
</div>
}
footer={<div className={style.FeedFooter}>Footer</div>}
/>
);
}
const itemData = [1, 2, 3, 4, 5];
نکته حرفه ای برای ایجاد طرح بندی با عناصر چسبنده
بسیاری از توسعه دهندگان تمایل به استفاده دارند position: fixed
یا position: absolute
وقتی می خواهند یک سرصفحه به بالای نمای نما یا یک پاورقی به پایین بچسبانند. با این حال ، در مورد طرح بندی ، باید سعی کنید از این امر جلوگیری کنید.
از آنجا که عناصر یک طرح ، عناصر اصلی لوازم جانبی ارسال شده خواهند بود ، شما می خواهید سبک عناصر طرح بندی خود را تا حد ممکن ساده نگه دارید – به این ترتیب <header>
، <main>
، یا <footer>
مطابق هدف طراحی شده اند بنابراین ، توصیه می کنم درخواست دهید position: fixed
و display: flex
به بیرونی ترین عنصر طرح و تنظیم شما overflow-y: scroll
به <main>
عنصر
در اینجا مثالی آورده شده است:
.Container {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
overflow: hidden;
position: fixed;
}
.Main {
width: 100%;
height: 100%;
overflow-y: scroll;
}
اکنون ، اجازه دهید برخی از سبک ها را در صفحه خوراک شما اعمال کنیم و ببینیم چه چیزی ساخته اید:
.FeedHeader {
height: 70px;
background-color: teal;
color: beige;
}
.FeedFooter {
height: 70px;
background-color: beige;
color: teal;
}
.ItemList {
display: flex;
flex-direction: column;
}
.Item {
height: 300px;
color: teal;
}
.FeedHeader,
.FeedFooter,
.Item {
display: flex;
justify-content: center;
align-items: center;
border: 1px solid teal;
font-size: 35px;
}
سربرگ چسبنده و نمایشی پاورقی
و در اینجا کد در عمل است.
این چیزی است که در صفحه های رومیزی به نظر می رسد.
این چیزی است که در صفحه نمایش تلفن همراه به نظر می رسد.
این طرح بندی در دستگاه های iOS نیز همانطور که در نظر گرفته شده کار می کند! در صورتی که نمی دانید ، iOS به دلیل ایجاد مشکلات غیرمنتظره مرتبط با موقعیت در توسعه برنامه های وب مشهور است.
2. شنونده رویداد
اغلب ، یک شنونده یک رویداد بیش از یک بار در سراسر یک برنامه وب استفاده می شود. در چنین شرایطی ، ایجاد یک قلاب سفارشی React ایده خوبی است. بیایید یاد بگیریم که چگونه این کار را با توسعه a انجام دهیم useScrollSaver
قلاب ، که موقعیت پیمایش دستگاه کاربر را در یک صفحه ذخیره می کند – به طوری که کاربر نیازی به حرکت مجدد همه از بالا ندارد. این قلاب برای یک صفحه وب مفید خواهد بود که در آن تعداد زیادی عنصر ، مانند پست ها و نظرات ذکر شده است. صفحات فید فیس بوک ، اینستاگرام و توییتر را بدون محافظ اسکرول تصور کنید.
بیایید کد زیر را تجزیه کنیم:
import { useEffect } from "react";
export default function useScrollSaver(scrollableDiv, pageUrl) {
const handleScroll = () => {
sessionStorage.setItem(
`${pageUrl}-scrollPosition`,
scrollableDiv.current.scrollTop.toString()
);
};
useEffect(() => {
if (scrollableDiv.current) {
const scrollableBody = scrollableDiv.current;
scrollableBody.addEventListener("scroll", handleScroll);
return function cleanup() {
scrollableBody.removeEventListener("scroll", handleScroll);
};
}
}, [scrollableDiv, pageUrl]);
useEffect(() => {
if (
scrollableDiv.current &&
sessionStorage.getItem(`${pageUrl}-scrollPosition`)
) {
const prevScrollPos = Number(
sessionStorage.getItem(`${pageUrl}-scrollPosition`)
);
scrollableDiv.current.scrollTop = prevScrollPos;
}
}, [scrollableDiv, pageUrl]);
}
شما می توانید ببینید که useScrollSaver
قلاب باید دو مورد را دریافت کند: scrollableDiv
، که باید مانند ظرف قابل پیمایش باشد <main>
ظرف در طرح شما در بالا ، و pageUrl
، که به عنوان شناسه یک صفحه استفاده می شود تا بتوانید موقعیت های پیمایش چندین صفحه را ذخیره کنید.
مرحله 1: موقعیت اسکرول را ذخیره کنید
اول از همه ، شما باید یک شنونده رویداد “scroll” را به ظرف قابل پیمایش خود متصل کنید:
const scrollableBody = scrollableDiv.current;
scrollableBody.addEventListener("scroll", handleScroll);
return function cleanup() {
scrollableBody.removeEventListener("scroll", handleScroll);
};
حالا ، هربار scrollableDiv
توسط کاربر پیمایش می شود ، تابع نامیده می شود handleScroll
اجرا خواهد شد در این تابع ، شما باید از هر دو استفاده کنید localStorage
یا sessionStorage
برای ذخیره موقعیت اسکرول تفاوت در این است که داده ها در localStorage
منقضی نمی شود ، در حالی که داده ها در sessionStorage
با پایان جلسه صفحه پاک می شود. شما می توانید استفاده کنید setItem(id: string, value: string)
برای ذخیره داده ها در هر دو ذخیره سازی:
const handleScroll = () => {
sessionStorage.setItem(
`${pageUrl}-scrollPosition`,
scrolledDiv.current.scrollTop.toString()
);
};
مرحله 2: موقعیت اسکرول را بازیابی کنید
هنگامی که یک کاربر به صفحه وب برمی گردد ، کاربر باید به موقعیت پیمایش قبلی خود هدایت شود – در صورت وجود. این اطلاعات موقعیت در حال حاضر در ذخیره می شود sessionStorage
، و شما باید آن را بیرون آورده و از آن استفاده کنید. شما می توانید استفاده کنید getItem(id: string)
برای به دست آوردن اطلاعات از ذخیره سازی سپس ، شما فقط باید تنظیم کنید scroll-top
ظرف قابل پیمایش به این مقدار بدست آمده:
const prevScrollPos = Number(
sessionStorage.getItem(`${pageUrl}scrollPosition`)
);
scrollableDiv.current.scrollTop = prevScrollPos;
مرحله 3: استفاده کنید useScrollSaver
در هر صفحه وب قلاب کنید
اکنون که ایجاد قلاب سفارشی خود را به پایان رسانده اید ، می توانید از قلاب در هر صفحه وب مورد نظر خود استفاده کنید تا زمانی که دو مورد مورد نیاز را به قلاب منتقل کنید: scrollableDiv
و pageUrl
به برگردیم به Layout.js
و از قلاب خود در آنجا استفاده کنید. این به هر صفحه وب که از این طرح استفاده می کند اجازه می دهد از محافظ پیمایش شما لذت ببرد:
import React, { useRef } from "react";
import style from "./Layout.module.css";
import PropTypes from "prop-types";
import useScrollSaver from "./useScrollSaver";
export default function Layout({ header, main, footer }) {
const scrollableDiv = useRef(null);
useScrollSaver(scrollableDiv, window.location.pathname);
return (
<div className={style.Container}>
<header className={style.Header}>{header}</header>
<main ref={scrollableDiv} className={style.Main}>
{main}
</main>
<footer className={style.Footer}>{footer}</footer>
</div>
);
}
نسخه نمایشی Scrollsaver
و در اینجا کد در Sandbox اجرا می شود. سعی کنید صفحه را پیمایش کنید ، سپس از پیکان در پایین سمت چپ و گوشه برای بارگیری مجدد برنامه استفاده کنید.
شما خود را در جایی که ترک کرده اید قرار خواهید گرفت!
3. Query/Mutation (مخصوص GraphQL)
اگر دوست دارید مانند من از GraphQL با React استفاده کنید ، می توانید با ایجاد یک قلاب React برای جستارها یا جهش های GraphQL ، پایگاه کد خود را حتی بیشتر کاهش دهید.
برای اجرای پرس و جو GraphQL مثال زیر را در نظر بگیرید getPosts()
:
import { gql, useQuery } from "@apollo/react-hooks";
const GET_POSTS = gql`
query getPosts {
getPosts {
user {
id
name
...
}
emojis {
id
...
}
...
}
`;
const { data, loading, error } = useQuery(GET_POSTS, {
fetchPolicy: "network-only"
});
اگر ویژگی های بیشتر و بیشتری برای درخواست از پشت وجود داشته باشد ، اسکریپت GraphQL شما فضای بیشتری را اشغال می کند. بنابراین ، به جای تکرار اسکریپت GraphQL و useQuery
هر بار که نیاز دارید پرس و جو را اجرا کنید getPosts()
، می توانید قلاب React زیر را ایجاد کنید:
import { gql, useQuery } from "@apollo/react-hooks";
export default function useGetPosts() {
const GET_POSTS = gql`
query getPosts {
getPosts {
user {
id
name
...
}
emojis {
id
...
}
...
}
`;
const { data, loading, error } = useQuery(GET_POSTS, {
fetchPolicy: "network-only"
});
return [data, loading, error];
}
سپس ، می توانید از دستگاه خود استفاده کنید useGetPosts()
به صورت زیر قلاب کنید:
import React from "react";
import Layout from "./Layout";
import style from "./Feed.module.css";
import useGetPosts from "./useGetPosts.js";
export default function Feed() {
const [data, loading, error] = useGetPosts();
return (
<Layout
header={<div className={style.FeedHeader}>Header</div>}
main={
<div className={style.ItemList}>
{data?.getPosts.map((item, idx) => (
<div key={idx} className={style.Item}>
{item}
</div>
))}
</div>
}
footer={<div className={style.FeedFooter}>Footer</div>}
/>
);
}
نتیجه
در این مقاله ، شما سه شاخص متداول یک جزء React را که قابل استفاده مجدد است ، و سه مورد از محبوب ترین موارد استفاده را آموخته اید. اکنون شما دانش آن را دارید چه زمانی برای ایجاد یک کامپوننت React قابل استفاده مجدد و چگونه به راحتی و حرفه ای این کار را انجام دهید. به زودی خواهید دید که از تغییر شکل خطوط کد در یک جزء پیچیده یا قلاب React استفاده می کنید. با استفاده از این تکنیک های تغییر شکل ، تیم توسعه ما در خاک رس توانست پایگاه کد ما را به اندازه قابل کنترل کاهش دهد. امیدوارم شما هم بتونید!