الگوی اجزای مرکب برای ایجاد جزء رتبه بندی قابل استفاده مجدد

👋 سلام مردم
این مقاله به شما توضیحی در مورد الگوی “کامپوننت های مرکب” می دهد.
🤔 چرا باید در مورد “کامپوننت اجزا” بدانم؟
“کامپوننت های مرکب” الگویی است که به ایجاد اجزای قابل استفاده مجدد و وابسته به یکدیگر کمک می کند. چنین الگوی به دستیابی به انزوا بهتر کمک می کند. این رویکرد به توسعه دهندگان اجازه می دهد تا به راحتی رابط های کاربری پویا و تعاملی ایجاد کنند و در عین حال کد را تمیز و منظم نگه دارند. این تنها یکی از مزایای استفاده از React و Component Component ها در توسعه وب است.
👨🔬 ممکن است یک توضیح تصویری به من نشان دهید؟
Rating
– جزء باید حاوی منطق برای ستاره های عظیم باشد و به راحتی مقیاس پذیر و قابل استفاده مجدد باشد.
این RatingItem
– کامپوننت باید منطق را مصرف کند Rating
جزء و فاقد هر گونه استایل، برای استفاده مجدد در پروژه ها یا طرح های مختلف. زیرا طراحی UI در آینده قابل تغییر است و ستاره شما تبدیل به یک لبخند یا چیز دیگری می شود.
👨🔬 خوب، قبل از اجرا، اجازه دهید در مورد آن توضیح دهم Rating
اجزای عمیق تر!
چه چیزی را باید در آن ذخیره کنیم Rating
جزء؟
- وضعیت رتبه بندی، در مورد ما از 1 تا 5 متغیر است.
- بولی شناور شد برای دانستن اینکه آیا کاربر ما روی مؤلفه رتبه بندی ما قرار دارد؟
- حالت شناور، از 1 تا 5، برای ایجاد یک تجربه رابط کاربری خوب.
آنچه در داخل خواهد بود RatingItem
جزء؟
- بدون سبک، زیرا طراحی می تواند در پروژه ها متفاوت باشد و تغییر آن دردسرساز خواهد بود
RatingItem
هر بار یک طرح جدید داریم. - کنترل کننده های مختلف، مانند
handleClick
یاhandleMouseLeave
، بسته به نیاز شما
👨💻 بیایید آن را کدگذاری کنیم!
folder structure
contexts/RatingContext.ts
providers/RatingProvider.ts
components/Rating.tsx
components/RatingItem.tsx
components/Feedback.tsx
1) ایجاد Context
و Provider
برای یک Rating
جزء.
contexts/RatingContext.ts
export const RatingContext = createContext({
rating: 0,
setRating: (_rating: number) => {},
hoverRating: 0,
setHoverRating: (_rating: number) => {},
isHovering: false,
setIsHovering: (_isHovering: boolean) => {},
});
providers/RatingProvider.ts
export const RatingProvider = RatingContext.Provider
ما در حال ایجاد Context
زیرا ما نیاز به انتقال اطلاعات داریم Rating
به RatingItem
، هر لانه ای که باشد.
2) ایجاد یک Rating
جزء با حالت اولیه مورد نیاز.
components/Rating/Rating.tsx
type Props = {
children: ReactNode
}
export const Rating: FC<Props> = ({ children }) => {
const [rating, setRating] = useState(0) // used to store the current rating
const [hoverRating, setHoverRating] = useState(0) // store information about the current hovered state
const [isHovering, setIsHovering] = useState(false) // information about is the rating hovered right now or not
const contextValue = useMemo(
() => ({
rating,
hoverRating,
isHovering,
setRating,
setHoverRating,
setIsHovering,
}),
[rating, hoverRating, isHovering],
)
return <RatingProvider value={contextValue}>{children}</RatingProvider>
}
3) بیایید یک قلاب برای مصرف ایجاد کنیم RatingContext
import { useContext } from "react"
import { RatingContext } from "../../contexts/RatingContext"
export const useRatingContext = () => {
const context = useContext(RatingContext)
if (!context) {
throw new Error("useRatingContext must be used within a RatingContext")
}
return context
}
📝 توجه داشته باشید: در اینجا، ما یک منطق “Compound Components” داریم. ایده این است که هر جا که بخواهیم از کامپوننت با این قلاب خارج از قلاب استفاده کنیم، این قلاب با خطا مواجه می شود
Rating
.
4) ایجاد <RatingItem />
جزء.
components/RatingItem.tsx
type Props = {
value: number
children: JSX.Element
}
export const RatingItem = ({ value, children }: Props) => {
const { setRating, rating, hoverRating, setHoverRating, setIsHovering } = useRatingContext()
return (
<span className="cursor-pointer">
{cloneElement(children, { needed_props_here })}
</span>
)
}
- پشتیبانی
value
برای انتقال اطلاعات در مورد اینکه چه مقدار از رتبه شما را نشان می دهد استفاده می شودRatingItem
بسته به نیاز شما مانند 1، 2 یا 0.5. -
useRatingContext
به مقادیر ارائه دهنده دسترسی می دهد. -
{cloneElement(children, { neededPropsHere })}
تمام لوازمی را که در آینده برای کنترل این حالت رابط کاربری آیکون لازم است در اختیار نماد شما قرار می دهد. ما در اینجا از cloneElement API استفاده می کنیم.
5) بهبود <RatingItem />
جزء با اضافه کردن کنترل کننده های اضافی.
export const RatingItem = ({ value, children }: Props) => {
const { setRating, rating, hoverRating, setHoverRating, setIsHovering } = useRatingContext()
// new code
const handleMouseEnter = () => {
setHoverRating(value)
setIsHovering(true)
}
const handleMouseLeave = () => {
setHoverRating(0)
setIsHovering(false)
}
const handleClick = () => {
if (rating === value) {
setRating(0)
return;
}
setRating(value)
}
const isCurrentRating = rating === value
const isHoveredRating = hoverRating === value
const isRatingNotSet = rating === 0
const isFilled = isRatingNotSet || isCurrentRating || isHoveredRating
return (
<span
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
onClick={handleClick}
className="cursor-pointer"
>
// end of new code
{cloneElement(children, { isFilled, isChoose: isCurrentRating })}
</span>
)
}
- ما کدی را برای مدیریت رویدادهای ماوس اضافه کردیم
handleClick
،handleMouseLeave
، وhandleMouseEnter
. - ما ثابت ها را اضافه کردیم
isCurrentRating
،isHoveredRating
،isRatingNotSet
، وisFilled
، که برای پیاده سازی الگوی UI مورد نیاز استفاده خواهد شد. این قسمت بسته به طرح شما می تواند متفاوت باشد!
6) ما تقریباً تمام منطق مورد نیاز برای نمایش امتیاز خود را ایجاد کردیم.
components/Feedback/feedback.tsx
export const Feedback = () => {
return (
<Rating>
<div className={styles.rating}>
<RatingItem value={1}>
<IconVeryBad />
</RatingItem>
<RatingItem value={2}>
<IconBad />
</RatingItem>
<RatingItem value={3}>
<IconNeutral />
</RatingItem>
<RatingItem value={4}>
<IconGood />
</RatingItem>
<RatingItem value={5}>
<IconVeryGood />
</RatingItem>
</div>
</Rating>
)
}
7) اما چه می شود اگر ما نیاز به دانستن در Feedback
جزء در حال حاضر چه رتبه ای است؟
components/Rating.tsx
type Props = {
children: ReactNode
onRatingChange?: (rating: number) => void // new prop onRatingChange
}
export const Rating: FC<Props> = ({ children, onRatingChange }) => {
const [rating, setRating] = useState(0)
const [hoverRating, setHoverRating] = useState(0)
const [isHovering, setIsHovering] = useState(false)
const contextValue = useMemo(
() => ({
rating,
hoverRating,
isHovering,
setRating,
setHoverRating,
setIsHovering,
}),
[rating, hoverRating, isHovering],
)
useEffect(() => {
onRatingChange?.(rating) // a prop function be called each time rating is changing
}, [rating])
return <RatingProvider value={contextValue}>{children}</RatingProvider>
}
-
onRatingChange
– تابعی که با تغییر رتبه توسط کاربر فراخوانی می شود.
8) استفاده از Rating
جزء
component/RatingFeedback.tsx
export const RatingFeedback = () => {
const [isShowText, setShowText] = useState(false)
const handleRatingChange = (rating: number) => {
if (rating > 0) {
setShowText(true)
setRating(rating)
} else {
setShowText(false)
setRating(0)
}
}
return (
<>
<Rating onRatingChange={handleRatingChange}>
<div className="flex justify-between w-full pointer-events-auto background-color-300 mt-4 max-w-[300px]">
<RatingItem value={1}>
<IconVeryBad />
</RatingItem>
<RatingItem value={2}>
<IconBad />
</RatingItem>
<RatingItem value={3}>
<IconNeutral />
</RatingItem>
<RatingItem value={4}>
<IconGood />
</RatingItem>
<RatingItem value={5}>
<IconVeryGood />
</RatingItem>
</div>
</Rating>
{isShowText && (
<label>
Please write to us
<textarea/>
</label>
)}
</>
)
}
-
handleRatingChange
هنگامی که کاربر رتبه بندی را انتخاب می کند، مسئول نمایش یک فیلد متنی است
🏁 خلاصه
در این مقاله، استفاده از “کامپوننت های ترکیبی” را برای ایجاد یک سیستم رتبه بندی با استفاده از React نشان دادیم. اجزای مرکب به شما این امکان را می دهد که با ترکیب اجزای ساده و قابل استفاده مجدد، اجزای رابط کاربری پیچیده ایجاد کنید. این رویکرد سازماندهی کد را بهبود می بخشد و نگهداری و گسترش آن را آسان تر می کند. مثالی که ما استفاده کردیم نشان داد که چگونه می توان یک سیستم رتبه بندی ایجاد کرد که هم کاربر پسند و هم قابل تنظیم باشد.
برای تست کد و مشاهده مثال در عمل، میتوانید لینک زیر را دنبال کنید: https://codesandbox.io/p/sandbox/compound-components-for-rating-y6getu.