سه اشتباهی که برنامه نویسان مبتدی React با state کامپوننت مرتکب میشن

از قشنگیای برنامه نویسی وب اینه که همیشه دانش جدید هست که یاد بگیری. میتونی کل عمرت رو بذاری زبان های برنامه نویسی، کتابخونه ها و فریم ورک های گوناگون رو مسلط بشی و آخرشم میبینی هنوزم همه چی رو نمیدونی.

چون در حال یادگیری هستیم، طبیعیه که اشتباه هم بکنیم. ایرادی نداره. هدف اینه که بهتر و بهتر بشیم. اگه اشتباه کنی و ازش درس بگیری، کارت درسته! ولی اگه اشتباهاتت رو تکرار کنی، خب... پس داری درجا میزنی.

بهمین جهت سه مورد از رایج ترین اشتباهاتی که برنامه نویسان مبتدی React بهنگام سر و کار داشتن با state کامپوننت مرتکب میشن رو برات لیست میکنم. نگاهی به هر مشکل میندازیم بعدش میگم چجوری اون مشکل رو حل کنی.

1. دستکاری مستقیم state

وقتی state کامپوننت رو تغییر میدی، مهمه که یک کپی جدید از state برگردونی، نه اینکه state فعلی رو مستقیما دستکاری کنی. اگه state رو بدرستی تغییر ندی، الگوریتم React تغییرات رو نمیگیره، و در نتیجه کامپوننت بدرستی آپدیت نمیشه. به این مثال نگاه کن.

فرض کن state این شکلیه:

this.state = {
  colors: ['red', 'green', 'blue']
}

و میخوای رنگ "زرد" رو به لیست اضافه کنی. وسوسه میشی این شکلی بنویسی:

this.state.colors.push('yellow')

یا شایدم این شکلی:

this.state.colors = [...this.state.colors, 'yellow']

ولی هر دو روش اشتباهه! وقتی state یک کامپوننت کلاس رو آپدیت میکنی، باید همیشه از متد setState استفاده کنی، و حواست باشه آبجکت هارو mutate نکنی. روش صحیح افزودن آیتم به این لیست این شکلیه:

this.setState(prevState => ({ colors: [...prevState.colors, 'yellow'] }))

2. آپدیت state قبلی بدون استفاده از فانکشن

دو روش برای استفاده از متد setState وجود داره. روش اول اینه که آرگومان آبجکت بهش بدیم. روش دوم اینه که بهش آرگومان فانکشن بدیم. خب، کجا از کدوم استفاده کنیم؟

فرض کن، یک دکمه داری که میتونه فعال یا غیرفعال باشه، ممکنه یک تیکه state به نام isDisabled داشته باشی که یک مقدار بولی داره. اگه بخوای این دکمه رو تغییر وضعیت بدی شاید وسوسه بشی آرگومان آبجکت بهش بدی:

this.setState({ isDisabled: !this.state.isDisabled })

خب، مشکل کجاست؟ مشکل اینه که در حقیقت آپدیت های state بسته بندی میشن، یعنی چندین آپدیت state میتونن در یک تک چرخه آپدیت اتفاق بیفتن. پس اگه چندین آپدیت برای وضعیت فعال و غیرفعال دکمه داری، نتیجه نهایی ممکنه اونطور که انتظار داری نباشه.

روش صحیح اینه که یک فانکشن بدیم که state قبلی رو بعنوان آرگومان میگیره:

this.setState(prevState => ({ isDisabled: !prevState.isDisabled }))

حالا، اگه حتی چندین آپدیت برای وضعیت داشته باشی، هر آپدیت به state قبلی تکیه میکنه بنابراین همیشه نتیجه ای که میگیری همونیه که میخوای.

این داستان برای مثلا افزودن تایمر هم صدق میکنه.

این شکلی ننویس:

this.setState({ counterValue: this.state.counterValue + 1 })

این شکلی بنویس:

this.setState(prevState => ({ counterValue: prevState.counterValue + 1 }))

3. یوقت فراموش کنی متد setState ناهمگامه

یادت باشه متد setState یک متد async یعنی ناهمگامه. بعنوان مثال، فرض کن کامپوننتی داریم با state این شکلی:

this.state = { name: 'John' };

و متدی داریم که state رو آپدیت میکنه و روی کنسول چاپ میکنه:

this.setState({ name: 'Matt' });
console.log(this.state.name);

شاید فکر کنی روی کنسول 'Matt' چاپ میشه، ولی نخیر! 'John' چاپ میشه!

دلیلشم اینه که، دوباره میگم، متد setState ناهمگامه. یعنی آپدیت state میره داخل صف و هر زمان نوبتش بشه صدا زده میشه، ولی خط کد دوم بی درنگ اجرا میشه چون کد ناهمگام روند اجرا رو بلاک نمیکنه.

اگه کدی داری که لازمه بعد از آپدیت state اجرا بشه، میتونی یک فانکشن callback به متد setState بدی.

پس مینویسیم:

this.setState({ name: 'Matt' }, () => console.log(this.state.name));

کلام آخر اینکه، یادت باشه اشتباه کردن هیچ ایرادی نداره. داری یاد میگیری دیگه، منم دارم یاد میگیرم. هممون داریم یاد میگیرم. پس همین روند رو ادامه بدیم تا بهتر و بهتر بشیم.