5 نکته برای جلوگیری از مشکلات React Hooks
من این پست وبلاگ را به عنوان سخنرانی ارائه کردم که می توانید آن را در اینجا مشاهده کنید:
ویژگی React Hooks بود
در اکتبر 2018 پیشنهاد شد و
صادر شده ~ 4 ماه
بعداً در فوریه 2019. از آن زمان، مردم به سرعت یاد می گیرند و
استفاده از قلاب ها در مبانی کد تولیدی خود، زیرا قلاب ها به طور چشمگیری ساده می شوند
مدیریت حالت و عوارض جانبی در برنامه ها
قطعاً به عنوان «خشم جدید» جایگاه شایسته خود را گرفته است. اما هر چقدر هم که گرم است،
React Hook نیاز به کمی تغییر در طرز فکر شما در مورد React Component دارد
چرخه زندگی، وضعیت و عوارض جانبی و شما به راحتی می توانید با مشکل مواجه شوید
اسکریپت ها اگر به درستی در مورد React Hooks فکر نمی کنید. پس بیایید نگاهی بیندازیم
در چه تله هایی می توانید بیفتید و چگونه می توانید فکر خود را از این طریق تغییر دهید
شما از آنها اجتناب می کنید
مستندات React Hooks درخشان است و من
اکیداً توصیه می کنم آن را تا انتها بخوانید
یک پرسش متداول که بسیار مفید است
اطلاعات بنابراین یک یا دو ساعت خوب وقت بگذارید و فقط مقالات را بدون آن بخوانید
صفحه کلید خود را لمس کنید این به شما یک نمای کلی مفهومی عالی از قلاب ها می دهد
و در وقت شما صرفه جویی می کند.
همچنین، فرصت را از دست ندهید
گفتگوهای React Conf توسط سوفی، دان و رایان در حال معرفی هوک ها.
برای جلوگیری از تله اول: اسناد و سوالات متداول را بخوانید 📚
در حوالی زمانی که هوکس منتشر شد،
eslint-plugin-react-hooks
بسته ساخته و منتشر می شود. دو قانون وجود دارد: “قوانین قلاب” و
“جزئیات جامع.” پیکربندی پیشفرض توصیهشده برای این خطمشیها بله است
“قوانین قلاب” را روی خطا و “جزئیات جامع” را روی هشدار تنظیم کنید.
من قویاً به شما توصیه می کنم که این قوانین را نصب، استفاده و دنبال کنید. این کار را نمی کند
فقط اشکالات واقعی را بگیرید که می توانید به راحتی از دست بدهید اما چیزهایی را نیز به شما یاد می دهند
در مورد کد شما و قلابهای موجود در فرآیند (بدون ذکر تصحیح خودکار عالی
تابع).
من با بسیاری از افرادی که از افزونه جامع deps اذیت شده اند صحبت کرده ام،
بنابراین اجازه دهید به سرعت سناریویی را نشان دهم که نادیده گرفتن این افزونه می تواند منجر به آن شود
اشکال:
تصور کنید یک صفحه دارید که لیستی از سگ ها را نشان می دهد و وقتی روی a کلیک می کنیدسگ، شما را به صفحه دیگری می برد که اطلاعات مربوط به آن سگ را نشان می دهد.
چیزی شبیه این:
خوب، بنابراین برای صفحه جزئیات ما یک DogInfo مولفه ای که الف را می پذیرد
dogId پشتیبانی و بازیابی اطلاعات سگ:
function DogInfo({ dogId }) {
const [dog, setDog] = useState(null)
// imagine you also have loading/error states. omitting to save space...
useEffect(() => {
getDog(dogId).then((d) => setDog(d))
}, []) // 😱
return div>{/* render the dog info here */}div>
}
ما احساس راحتی می کنیم که از وابستگی های آرایه در آنجا صرف نظر کنیم زیرا این امر
درخواست باید فقط در هنگام نصب انجام شود. و همانطور که همه چیز امروز است، ما خواهیم بود
خوب اما حالا بیایید تصور کنیم که UI کمی تغییر می کند و شروع به لیست کردن a می کنیم
رابط کاربری “سگ های متصل” در این صفحه. ما یک اشکال و یک کلیک روی آن خواهیم داشت
سگ متصل، اطلاعات سگ را بهروزرسانی نمیکند، حتی اگر جزء آن باشد
دوباره منتشر شد! مشاهده کنید (روی Poodle و سپس در قسمت Related Dogs کلیک کنید
“Bernedoodle” و متوجه هیچ تغییری نشدید):
بنابراین باعث ایجاد یک رندر مجدد از ما می شود DogInfo با یک جدید dogId، اما به دلیل
ما یک آرایه وابستگی خالی ارائه کردیم، افکت ما دوباره اجرا نمی شود.
پس بیایید این وابستگی را اضافه کنیم:
function DogInfo({ dogId }) {
const [dog, setDog] = useState(null)
// imagine you also have loading/error states. omitting to save space...
useEffect(() => {
getDog(dogId).then((d) => setDog(d))
}, [dogId]) // ✅
return div>{/* render the dog info here */}div>
}
عالی ترین در اینجا نحوه عملکرد آن در حال حاضر است:
نکته اصلی این مثال در اینجا آمده است: اگر واقعاً هرگز تغییر نخواهد کرد، پس
به هر حال روشن کردن آن ضرری ندارد. همچنین، اگر فکر می کنید هرگز تغییر نخواهد کرد
و این کار را انجام می دهد، از جمله به شما کمک می کند از اشتباه جلوگیری کنید.
موقعیت های بسیار دیگری وجود دارد که غلبه بر آنها بدتر و دشوارتر است
شناسایی/توضیح (مثلاً اگر اضافه کردن یک تابع به لیست وابستگی را از دست دادید
ممکن است آن را یک بسته شدن کهنه بنامید). فقط به من اعتماد کن، هر بار که فکر کردم “اوه
این بار نیازی به پیروی از این قانون ندارم» بعداً از غیرفعال کردن آن پشیمان شدم
چون اشتباه کردم
لطفاً توجه داشته باشید که گاهی اوقات این قانون نمی تواند به صورت ایستا اجرا شود
به لطف محدودیت های ابزارهای تحلیل استاتیک، کد خود را به درستی تجزیه و تحلیل کنید
مانند ESLint. من معتقدم که به همین دلیل است که عمقهای کامل تنظیم میشوند
قانون “هشدار” به جای “خطا”. وقتی این اتفاق می افتد، افزونه به شما اطلاع می دهد
بنابراین در هشدار من توصیه می کنم سعی کنید کد خود را کمی تغییر ساختار دهید
از این اخطار اجتناب کنید (لطفاً وضوح را به حقه ترجیح دهید). اگر این اتفاق نیفتد
کار کنید، سپس غیرفعال کردن افزونه راه نجات شماست تا بتوانید به کار خود ادامه دهید.
برای جلوگیری از تله دوم: افزونه ESLint را نصب، استفاده و دنبال کنید 👨🏫
از زمانی که React محبوب بود (قبل از هوک)، ما یک مورد خوب و واضح داشتیم
مؤلفه API که گفتن React را برای ما آسان کرد چه زمانی باید حتما انجام داد
چیزها:
class LifecycleComponent extends React.Component {
constructor() {
// initialize component instance
}
componentDidMount() {
// run this code when the component is first added to the page
}
componentDidUpdate(prevProps, prevState) {
// run this code when the component is updated on the page
}
componentWillUnmount() {
// run this code when the component is removed from the page
}
render() {
// call me anytime you need some react elements...
}
}
نوشتن مؤلفههایی مانند این هنوز کار میکند (و برای آینده قابل پیشبینی هم کار خواهد کرد)،
و سالها بسیار خوب کار کرد. قلاب ها مزایای زیادی دارند، اما یکی از موارد مورد علاقه من این است که باعث می شود اجزای شما در مورد آن شفاف تر باشند.
به شما این امکان را می دهد که فکر نکنید «زمانی که چیزهایی باید در چرخه زندگی اتفاق بیفتند
جزء» (که چندان اهمیتی ندارد) و بیشتر درباره «وقتی چیزها
باید در ارتباط با تغییرات حالت رخ دهد» (که معنای بسیار بیشتری دارد).
بنابراین اکنون داریم:
function HookComponent() {
React.useEffect(() => {
// This side effect code is here to synchronize the state of the world
// with the state of this component.
return function cleanup() {
// And I need to cleanup the previous side-effect before running a new one
}
// So I need this side-effect and it's cleanup to be re-run...
}, [when, any, ofThese, change])
React.useEffect(() => {
// this side effect will re-run on every single time this component is
// re-rendered to make sure that what it does is never stale.
})
React.useEffect(() => {
// this side effect can never get stale because
// it legitimately has no dependencies
}, [])
return /* some beautiful react elements */
}
رایان فلورانس به شکل دیگری این را به خوبی بیان کرد:
دلیل اینکه من آن را بسیار دوست دارم این است که به طور طبیعی به من کمک می کند تا از اشتباهات جلوگیری کنم. و همینطور
من اغلب متوجه شدهام که در کدم با خطا مواجه شدهام، زیرا فراموش کردهام که Prop یا را کنترل کنم
به روز رسانی وضعیت در componentDidUpdate، و وقتی به یاد می آوردم، اغلب این کار را می کردم
فراموش کنید که قبل از شروع عارضه جانبی جدید، عارضه جانبی قبلی را پاک کنید (مثلاً
برای مثال، اگر یک درخواست HTTP داشته باشید، اما پیش از آن درخواست تغییر کند
تکمیل شد، باید درخواست قبلی را لغو کنید).
با React Hooks، هنوز به این فکر می کنید که چه زمانی باید عوارض جانبی رخ دهد.
اما شما به چرخه عمر اجزا فکر نمی کنید، بلکه به آن فکر می کنید
همگام سازی وضعیت عوارض جانبی با وضعیت برنامه.
گرفتن آن کمی به عادت کردن نیاز دارد، اما این ایده بسیار قدرتمندی است
که وقتی آن را بپیچید، طبیعتا باگ های کمتری را تجربه خواهید کرد
در برنامه های شما به لطف طراحی API.
بنابراین وقتی فکر می کنید، «هی، لیست اعتیاد من باید باشد []“نکن
از آنجایی که فکر میکنید فقط در صورت نصب باید کار کند، این کار را انجام دهید زیرا میدانید
که کارهایی که انجام می دهد هرگز قدیمی نمی شوند.
برای جلوگیری از این تله: به چرخه های زندگی فکر نکنید، به همگام سازی فکر کنید
عوارض جانبی که باید لیست کنید 🔄
به دلایلی وقتی برخی از مردم این را می بینند عصبانی می شوند:
function MyComponent() {
function handleClick() {
console.log('clicked some other component')
}
return SomeOtherComponent onClick={handleClick} />
}
2 دلیل وجود دارد که مردم در این مورد نگران هستند:
- ما تابع را در داخل کامپوننت تعریف می کنیم، یعنی می شود
هر بار دوباره تعریف می شودبه تصویر کشیده شده است - ما این تابع جدید تعریف شده را به عنوان یک پایه به آن منتقل می کنیم
یعنی نمی توان آن را به درستی بهینه کرد
React.memo،React.PureComponent، یاshouldComponentUpdateو اراده
از “بازسازی های غیر ضروری” رنج می برند
برای اولین نکته، موتورهای جاوا اسکریپت (حتی موتورهای تلفن همراه پایین رده)
در تعریف توابع بسیار سریع هستند. خیلی بعید است که با آن روبرو شوید
مشکل با (دوباره) تعریف توابع زیاد.
در مورد نکته دوم، «رندر مجدد غیر ضروری» لزوماً عملکرد بدی نیست. فقط به این دلیل که یک کامپوننت دوباره رندر می شود به این معنی نیست که DOM دریافت می کند
به روز شد (به روز رسانی DOM ممکن است کند باشد). React در بهینه سازی کار بسیار خوبی انجام می دهد
بنابراین لازم نیست کارهای عجیب و غریبی با کد خود انجام دهید تا آن را سریع کنید. این است
به صورت پیش فرض سریع
اول، اگر رندرهای غیرضروری برنامه شما باعث کند اجرای آن شود
بررسی کنید چرا رندرها کند هستند. اگر رندر برنامه شما آنقدر کند است که چندین
رندرهای اضافی باعث تأخیر قابل توجهی میشوند، پس احتمالاً هنوز هم خواهید داشت
هنگام فشار دادن “Rerenders مورد نیاز” مشکلات عملکردی وجود دارد. هنگامی که آنچه را که هست درست کنید
با کند کردن رندر، ممکن است متوجه شوید که رندر مجدد غیر ضروری باعث نمی شود
مشکلات برای شما در حال حاضر
اگر تصمیم گرفتید که رندر مجدد غیر ضروری باعث بهره وری شما می شود
پس از آن می توانید API های داخلی بهینه سازی عملکرد را باز کنید
React لایک هایی در دسترس شما دارد React.memo، React.useMemo، و
React.useCallback. از پست وبلاگ من بیشتر بیاموزید
useMemo و useCallback. این را به خاطر بسپار
گاهی اوقات می توانید بهینه سازی عملکرد را اعمال کنید و برنامه شما واقعاً کار می کند
کندتر پس اول اندازه بگیرید!
همچنین به یاد داشته باشید که
نسخه تولیدی React سریعتر از نسخه توسعه است
برای جلوگیری از این تله: بدانید که React به طور پیش فرض سریع است و کمی جستجو کنید
قبل از اعمال بهینه سازی عملکرد پیش از موعد 🏎💨
متوجه شده ام که برخی از افراد نگران بازنویسی تست های خود هستند
همراه با تمام اجزای آنها هنگام تبدیل به قلاب. این ممکن است یا ممکن است
بسته به نحوه نگارش تست های شما درست نیست.
برای قرض گرفتن از پست من”React Hooks: چه اتفاقی برای آزمایشات من خواهد افتاد؟”،
اگر تست های خود را اینگونه نوشتید:
test('setOpenIndex sets the open index state properly', () => {
// using enzyme
const wrapper = mount(Accordion items={[]} />)
expect(wrapper.state('openIndex')).toBe(0)
wrapper.instance().setOpenIndex(1)
expect(wrapper.state('openIndex')).toBe(1)
})
سپس می توانید به این به عنوان یک فرصت عالی برای بهبود تست های خود نگاه کنید! شما خواهد شد
شما قطعا باید این تست را حذف کنید و در عوض آن را اینگونه بنویسید:
test('can open accordion items to see the contents', () => {
const hats = { title: 'Favorite Hats', contents: 'Fedoras are classy' }
const footware = {
title: 'Favorite Footware',
contents: 'Flipflops are the best',
}
const items = [hats, footware]
// using React Testing Library
render(Accordion items={items} />)
expect(screen.getByText(hats.contents)).toBeInTheDocument()
expect(screen.queryByText(footware.contents)).toBeNull()
userEvent.click(screen.getByText(footware.title))
expect(screen.getByText(footware.contents)).toBeInTheDocument()
expect(screen.queryByText(hats.contents)).toBeNull()
})
تفاوت اصلی در اینجا این است که اولی اجرا را آزمایش می کند
جزئیات جزء و جدید نیست. خواه جزء شما باشد
پیاده سازی شده از طریق Hooks یا به عنوان یک کلاس یک جزئیات پیاده سازی است
جزء بنابراین، اگر تست شما به گونه ای نوشته شده باشد که این را آشکار کند
(مثل استفاده .state() یا .instance()، سپس کامپوننت خود را مجدداً در آن قرار دهید
قلاب ها به طور طبیعی باعث شکستن خمیر شما می شوند.
اما کاربر نهایی اهمیتی نمیدهد که اجزای شما بهعنوان حفره یا کلاس نوشته شوند. آنها فقط علاقه مند هستند که بتوانند با کسی که هستند ارتباط برقرار کنند
کامپوننت ها روی صفحه نمایش داده می شوند. بنابراین اگر تست های شما با آنچه که وجود دارد ارتباط برقرار کند
رندر شده است، پس مهم نیست که چگونه این چیزها روی صفحه نمایش داده می شوند،
همه چیز کار می کند چه از کلاس ها و چه از قلاب ها استفاده کنید.
می توانید در مورد آن اطلاعات بیشتری کسب کنید
جزئیات اجرای تست و
از کاربر آزمایشی خودداری کنید.
بنابراین، برای جلوگیری از این تله: از آزمایش جزئیات عملکرد خودداری کنید 🔬
برای بررسی، در اینجا نکاتی وجود دارد که میخواهم به شما کمک کنم تا از آن اجتناب کنید
برخی از مشکلات قلاب:
- اسناد و سوالات متداول را بخوانید 📚
- افزونه ESLint را نصب، استفاده و دنبال کنید 👨🏫
- به چرخه زندگی فکر نکنید، به زمان بندی عوارض جانبی برای بیان فکر کنید
🔄 - بدانید که React به طور پیشفرض سریع است و قبل از پیادهسازی کمی حفاری کنید
بهینه سازی عملکرد پیش از موعد 🏎💨 - از آزمایش جزئیات عملکرد خودداری کنید 🔬
امیدوارم این برای شما مفید باشد! قلابها برنامههای من را کمتر باگ میکنند و باعث میشوند
سازنده تر اگرچه نمی توان انکار کرد که قلاب ها منحنی یادگیری دارند
(اگر مدتی از React استفاده می کنید، ممکن است واضح تر باشد)، ارزشش را دارد
سرمایه گذاری




