برنامه نویسی

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

👋 سلام مردم

این مقاله به شما توضیحی در مورد الگوی “کامپوننت های مرکب” می دهد.

🤔 چرا باید در مورد “کامپوننت اجزا” بدانم؟

“کامپوننت های مرکب” الگویی است که به ایجاد اجزای قابل استفاده مجدد و وابسته به یکدیگر کمک می کند. چنین الگوی به دستیابی به انزوا بهتر کمک می کند. این رویکرد به توسعه دهندگان اجازه می دهد تا به راحتی رابط های کاربری پویا و تعاملی ایجاد کنند و در عین حال کد را تمیز و منظم نگه دارند. این تنها یکی از مزایای استفاده از React و Component Component ها در توسعه وب است.

👨‍🔬 ممکن است یک توضیح تصویری به من نشان دهید؟

Rating – جزء باید حاوی منطق برای ستاره های عظیم باشد و به راحتی مقیاس پذیر و قابل استفاده مجدد باشد.

این RatingItem – کامپوننت باید منطق را مصرف کند Rating جزء و فاقد هر گونه استایل، برای استفاده مجدد در پروژه ها یا طرح های مختلف. زیرا طراحی UI در آینده قابل تغییر است و ستاره شما تبدیل به یک لبخند یا چیز دیگری می شود.

توضیح سطح بالای جزء رتبه بندی

👨‍🔬 خوب، قبل از اجرا، اجازه دهید در مورد آن توضیح دهم Rating اجزای عمیق تر!

چه چیزی را باید در آن ذخیره کنیم Rating جزء؟

  • وضعیت رتبه بندی، در مورد ما از 1 تا 5 متغیر است.
  • بولی شناور شد برای دانستن اینکه آیا کاربر ما روی مؤلفه رتبه بندی ما قرار دارد؟
  • حالت شناور، از 1 تا 5، برای ایجاد یک تجربه رابط کاربری خوب.

آنچه در داخل خواهد بود RatingItem جزء؟

  • بدون سبک، زیرا طراحی می تواند در پروژه ها متفاوت باشد و تغییر آن دردسرساز خواهد بود RatingItem هر بار یک طرح جدید داریم.
  • کنترل کننده های مختلف، مانند handleClick یا handleMouseLeave، بسته به نیاز شما

ساختار پیاده سازی Compound Components

👨‍💻 بیایید آن را کدگذاری کنیم!

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.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا