هوک useOverflow: کی متن واقعاً بریده شده؟
خلاصهٔ کاملتر
مشکل آشناست: یه توضیح طولانی داری و با کلاس line-clamp-3 (یعنی متن فقط تا سه خط نشون داده بشه و بقیهش مخفی بشه) کوتاهش میکنی. حالا باید تصمیم بگیری دکمهٔ «Show more» رو نشون بدی یا نه. نویسنده میگه چون بریدن متن کار CSS هست، فقط مرورگر میدونه چیزی واقعاً پنهان شده یا نه.
راهحلش مقایسهٔ دو عدده: scrollHeight یعنی ارتفاع کل محتوا، و clientHeight یعنی ارتفاع کادری که دیده میشه. اگه اولی بزرگتر باشه، یعنی یه بخشی از متن بریده شده. ولی این جواب ثابت نیست؛ کادر که باریکتر بشه، خطها بیشتر میشکنن و ممکنه متنی که قبلاً جا میشد حالا بیرون بزنه. برای همین هوک از ResizeObserver (یه API مرورگر که با هر تغییر اندازهٔ المنت خبرت میکنه) استفاده میکنه تا با هر resize دوباره اندازه بگیره.
استفادهش توی کامپوننت این شکلیه:
const ref = useRef<HTMLParagraphElement>(null)
const [expanded, { toggle }] = useToggle()
const overflows = useOverflow(ref, { axis: 'y', paused: expanded })گزینهٔ paused اندازهگیری رو متوقف میکنه و آخرین نتیجه رو نگه میداره. این مهمه، چون وقتی کاربر متن رو باز میکنه دیگه چیزی بریده نیست و بدون paused دکمهٔ «Show less» هم غیب میشد. دکمه هم با شرط overflows || expanded نشون داده میشه.
خود اندازهگیری روی دو محور کار میکنه. توی محور افقی scrollWidth با clientWidth مقایسه میشه، ولی توی محور عمودی یه پیکسل اختلاف نادیده گرفته میشه، چون گرد شدن ارتفاع خطها در حد کسری از پیکسل میتونه یه overflow الکی نشون بده:
const measure = () =>
setOverflows(
axis === 'x'
? el.scrollWidth > el.clientWidth
: el.scrollHeight - el.clientHeight > 1,نکات کلیدی:
- معیار overflow مقایسهٔ scrollHeight با clientHeight (یا scrollWidth با clientWidth برای محور x) هست.
- ResizeObserver با هر تغییر اندازه، نتیجه رو دوباره حساب میکنه.
- توی محور عمودی تا ۱ پیکسل اختلاف به خاطر گرد شدن line-height نادیده گرفته میشه.
- گزینهٔ paused موقع باز بودن متن، آخرین نتیجه رو نگه میداره تا دکمهٔ «Show less» غیب نشه.
- هوک با 'use client' نوشته شده، یعنی برای کامپوننتهای سمت کلاینت توی React/Next.js هست.




