یکی از سوال هایی که داخل گروه های برنامه نویسی خیلی زیاد میبینم بچه ها میپرسن همین سوال بالا هست. تو ذهنمه از جادی شنیدم هر چیزی رو سه بار تو گپ های برنامه نویسی پرسیدن مقاله کن. خلاصه تو این مقاله میخوایم در همین مورد حرف بزنیم که قبل از کارکردن با ری اکت باید چیا رو بلد باشیم که سریع تر ری اکت رو یادبگیریم، درکش کنیم و ازش استفاده کنیم.
خب همین اول کار لیستشون رو اینجا میارم که جمع و جور یک جا داشته باشیدشون، واسه بقیه مقاله هم بررسیشون میکنم.
خب اولین چیزی که میریم سراغشون شی گرایی و کلس ها در جاوااسکریپت هستن ببینید در کل سه روش واسه پیاده کردن شی گرایی در جاوااسکریپت وجود داره
1-Object.create()
2-Constructor functions
3-ES6 Classes
خب اولی رو کاری باهاش نداریم چون خیلی کم استفاده میشه، میمونه Constructor functions, ES6 Classes.
قبلا شی گرایی در جی اس با استفاده از Constructor functions انجام میشد ولی یکم بعد اومدن کلس هارو به جاوااسکریپت اضافه کردن واسه اینکه از نظر سینتکسی اسون تر بشه شی گرایی رو پیاده کرد. یک مثال ساده بخوام ازش بزنم و جز اولین چیز هایی هست که شما با یادگیری ری اکت میبینیدش کلس کامپوننت ها(اجزای صفحه مثل باتن هدر و...) هستن.
import React from "react" class App extends React.Component { render() { return <h1>Hello React</h1>; } } export default App;
این کد میاد یک کامپوننت به اسم App رو صفحه رندر میکنه که یک تگ h1 رو نمایش میده.
داخل همین چند خط میبینیم که کلس App میاد خواص خودش رو از کلس Component از لایببری ری اکت به ارث میبره و از متود render هم استفاده میکنه پس مشخصه که باید کلس هارو بلد باشیم.
شما ممکنه کاملا کد هارو متوجه نشید و طبیعی هم هست چون هنوز ری اکت کار نکردید، هدف مقاله هم صرفا اشنایی شما با این مفاهیم هست و اینکه بدونید این مفاهیم بسیار پر استفاده هستن و یادگیریشون قبل از شروع ری اکت لازمه. در هر صورت اگه میخواید که کد هارو خودتون اجرا کنید من لینک codesandbox رو این پایین میذارم.
https://codesandbox.io/s/tender-williams-7mdl7
از arrow function ها هم خیلی زیاد استفاده میشه داخل ری اکت و حتما باید بلدشون باشید.
arrow function ها یک سری فانکشن اکسپرشن(هر واحد صحیحی از کد که به یک مقدار ختم شه رو اکسپرشن میگن) های جمع و جور هستن که مزایا و معایب خودشون رو دارن و باید در جای مناسبش استفاده بشن. بذارید مثالی که تو ری اکت ازشون استفاده میشه رو بزنم.
import React from "react" const App = () => { const [value, setValue] = React.useState('React') return ( <> <h1>Hello {value}</h1> <input type="text" ={e => setValue(e.target.value)}/> </> ); } export default App;
تو کد بالا میبینید که دو بار از arrow function ها استفاده شده، یک بار واسه ساختن از یک کامپوننت و یک بار داخل ایونت واسه ریختن مقدار داخل اینپوت داخل تگ h1.
یه کاربرد خیلی خوب دیگه هم دارن که جلوتر بهش میپردازیم.
یه ویژگی خیلی خفنی که مدتیه به زبان جاوااسکریپت اضافه شده همین چیزی هست که تیترش رو بالا نوشتم. destructuring رو به کرات داخل اکوسیستم جاوااسکریپت میبینید که استفاده میشه.
این ویژگی به ما اجازه میده که مقدار هارو از ارایه unpack کنیم حالا یعنی چی بذارید مثال بزنم
const colors = ['red', 'green', 'blue']; // without using destructuring const red = colors[0] const green = colors[1] const blue = colors[2] // using destructuring const [red, green, blue] = colors
می بینید که خیلی کوتاه تر و خواناتر تونستیم مقدار هارو از ارایه دربیاریم. خب این خیلی پر استفادست داخل ری اکت یک استفادش رو تو قسمت arrow functions دیدیم در واقع.
// without using destructuring const useState = React.useState('React') const value = useState[0] const setValue = useState[1] // using destructuring const [value, setValue] = React.useState('React')
میتونیم destructuring رو روی ابجکت ها هم پیاده کنیم، به این شکل:
const info = { name: 'javascript', age: 26 } const {name, age} = info console.log(name, age) // javascript 26 function Log({name, age}) { console.log(`My name is ${name}, I am ${age} years old.`) } Log(info) // My name is javascript, I am 26 years old.
یه مبحث دیگه که خیلی باهاش هم توی وانیلا جاوااسکریپت هم داخل فریمورک ها و لایبرری ها باهاش سر و کار داریم متود های ارایه هستن. توصیه میکنم حتما اکثرشون رو که استفاده میشن رو یاد بگیرید. سه تا از این ها که خیلی داخل ری اکت استفاده میشن map, reduce, filter هستن. من اینجا به map اشاره میکنم چون خیلی زیاد ازش استفاده میشه. متود map میاد به ازای هر المنت در ارایه یک فانکشنی رو روی المنت اجرا میکنه و مقدار رو map میکنه. اول یک مثال ساده ازش میزنم و بعد یک کاربردش که توی ری اکت خیلی ازش استفاده میشه.
const arr = [1, 2, 3, 4, 5] const multipliedArr = arr.map(el => el * 2) console.log(multipliedArr) // [2, 4, 6, 8, 10]
خب تو این مثال میبینید که به ازای هر عنصر ما اومدیم یک فانکشن اجرا کردیم که مقدار رو دو برابر کرد.
حالا توی ری اکت چطور استفاده میشه؟ فرض کنید شما یک سری data دارید مثل کالا ها، کاربر ها یا هرچیز دیگه که با درخواست به یک API اون data رو میگیرید و میخواید اون رو صفحه نمایش بدید.
خب روش کار اینجوریه که ما میایم data رو میگیریم و بعد به ازای هر المنت در data یک کامپوننت رندر میکنیم تو صفحه، به این شکل:
import React, {useEffect, useState} from "react" const App = () => { const [posts, setPosts] = useState(null) useEffect(() => { const fetchData = async () => { const response = await fetch('https://jsonplaceholder.typicode.com/posts') const data = await response.json() setPosts(data) } fetchData() }, []) return ( <ul> {posts ? posts.map(post => <li key={post.id}>{post.title}</li>) : <h1>Loading</h1>} </ul> ) } export default App;
توی کد بالا یک سری post از API گرفته شدن و تیتر هاشون داخل یک تگ li قرار گرفت و رو صفحه نمایش داده شد.
خب از دیگر کانسپت هایی که توی دنیای جاوااسکریپت نه تنها ری اکت وجود داره و جزو ضروریات هست Ajax یا Asynchronous javascript and xml هست. کل قضیه اش این هست که یک سری کارها مثل گرفتن data از API زمان میبره و sync (همگام) نیست یعنی همون موقع مثل خیلی دیگه از دستورها خط به خط اجرا نمیشه.
ما تو این حالت میایم درخواست میزنیم به یک API و data رو میگیریم و رو صفحه نمایش میدیم. مثلا توی سایت یوتیوب وقتی چیزی رو سرچ میکنیم یک درخواست میره سمت بک اند و ویدیو هایی که با سرچ ما مرتبط هستن برمیگردن و رو صفحه نمایش داده میشن. یا مثلا وقتی تو یک سایت ثبت نام میکنیم data ای که داخل فرم ها پر کردیم فرستاده میشن.
و همه این کار ها به صورت async (ناهمگام) رخ میده و یکمی زمان میبره حالا بستگی به حجم data و سرعت نت و... .
واسه فرستادن درخواست سمت بک اند و گرفتن data یا فرستادن چند روش وجود داره قدیمی ترین روش استفاده از XMLHttpRequest هست که دیگه استفاده نمیکنیم ازش. بعد از اون Promise ها اومدن و بعدش هم async/await.
دقت داشته باشید که async/await در نهایت به همون Promise ها تبدیل میشن ولی واسه راحتی کار به زبان اضافه شدن(چون Promise ها میتونن تو در تو بشن و از نظر خوانایی مشکل ایجاد کنن و به اصطلاح callback hell ایجاد کنن). واسه مثال هم در اصل تو مبحث قبلی شما یک مثال ازش دیدید:
// using Promise const fetchData = () => { fetch('https://jsonplaceholder.typicode.com/posts').then(response => response.json()).then(data => console.log(data)) } fetchData() // using async await const fetchData = async () => { const response = await fetch('https://jsonplaceholder.typicode.com/posts') const data = await response.json() console.log(data) } fetchData()
توی کد بالا ما اومدیم با درخواست به سایتی که بالا میبینید یک سری data رو گرفتیم و لاگشون کردیم. هر دو کد یک کار رو انجام میدن اما بالایی با Promise ها نوشته شده و پایینی با async await.
راستی Extensible Markup Language/XML که بالاتر دیدید فرمت data ای بود که قبلا با API رد و بدل میشد. الان از javascript object notation/JSON استفاده میشه که احتمالا اسمش رو شنیدید.یک اسم اشنا هم که جلوتر خواهید شنید اگه تا حالا نشنیدید axios هست.یک لایببری هست که اجازه میده بهمون درخواست ajax بزنیم و یک سری مزیت در اختیارمون قرار میده.
خب این مبحث چیز خاصی نداره ولی خیلی مهمه و باید بلدش باشید. قضیه اینه که با بزرگ شدن پروژه حجم فایل ها خیلی زیاد میشه و مدیریتش سختتر واسه همین با میایم کد هامون رو داخل فایل هم مختلف قرار میدیم و ازشون داخل هم دیگه استفاده میکنیم. مثلا تو کد های بالا دیدید که من اومدم کتابخونه react رو import (وارد) کردم داخل پروژه خودم و ازش استفاده کردم.
چیز خاصی نداره میتونید با سرچ تو یوتیوب سریع یادش بگیرید چیزی که من اینجا اشاره میکنم بهش Named export, Default export هست.
// Named export export const name = 'value' // Named import import {name} from '...' // Default export export default 'value' // Default import import anyName from '...'
وقتی از Named export استفاده میکنیم باید اسم چیزی که import میکنیم دقیقا برابر با چیزی باشه که export کردیم و باید داخل {} بذاریمش.یک نکته دیگه هم اشاره کنم این هست که به ازای هر فایل فقط میتونیم یک Default export داشته باشیم.
یک چیزی که خیلی خیلی مهمه شما بلدش باشید نحوه رفتار this در جاهای مختلف هست. this مقدارش static نیست شما باید بدونید هر موقع که ازش استفاده میکنید دقیقا مقدارش چی هست و به چی برمیگرده. باید بدونید نحوه رفتارش داخل arrow function ها یا class ها به چه شکل هست، در غیر این صورت به مشکل میخورید.
یه مثال بزنم فرض کنید شما همچین کدی دارید:
import React from "react" class App extends React.Component { state = { counter: 0 } increase() { this.setState((state) => ({ counter: ++state.counter })) } render() { return ( <> <h1>{this.state.counter}</h1> <button ={this.increase}>increase</button> </> ) } } export default App;
خب تو کد بالا چیزی که انتظار داریم اینه که this داخل متود increase به کلس App برگرده و متود setState رو فراخوانی کنه اما چیزی که اتفاق میفته اینه که this اینجا به Window اشاره میکنه و چون متود setState داخلش وجود نداره ارور برمیگردونه. این یک ارور رایجه بین کسایی که تازه ری اکت رو شروع میکنن، دو تا راه حل براش هست یکی اینکه بیایم this رو bind (متصل) کنیم به کلس App یعنی:
<button ={this.increase}>increase</button> // wrong❌ <button ={this.increase.bind(this)}>increase</button> // correct✅
و یک روش دیگه که روش بهتری هم هست بیایم از arrow functions ها واسه تعریف متود استفاده کنیم که خودش اتوماتیک this رو bind میکنه یعنی :
increase(){ this.setState((state) => ({ counter: ++state.counter })) } // fine? increase = () => { this.setState((state) => ({ counter: ++state.counter })) } // best practice✅
این همون ویژگی بود که گفتم درباره arrow functions بعدا بهش اشاره میکنم. این فانکشن ها this خودشون رو نمیگیرن و وقتی از this داخلشون استفاده میکنیم به scope بالاتر از خودشون اشاره میکنن(به این میگن lexical this) مثلا اگه داخل global scope از this استفاده کنیم به Window برمیگرده.
خب این دوتا فیچر هم که به زبان اضافه شدن خیلی فیچر های خفنی هستن Spread Operator بهمون اجازه میده که مقادیر یک iterable (ارایه برای مثال) رو بگیریم و به المنت های مجزا تبدیلش کنیم.
Rest Parameter هم اجازه میده که یک سری المنت های نامعین رو بریزیم داخل یک ارایه و بهشون دسترسی داشته باشیم. بهش میگن Rest(باقی مانده) چون مثل مثال بالا باقی مانده المنت هارو جمع میکنه داخل یک ارایه. با کد نشون بدم بهتر متوجه میشید:
// in spread we expand in rest we compress // Spread , becuase on RIGHT side of = const arr = [1, 2, ...[3, 4]]; console.log(arr); (4) [1, 2, 3, 4] // the rest syntax takes multiple values and pack them into one array // Rest, becuase on LEFT side of = const [a, b, ...others] = [1, 2, 3, 4, 5]; console.log(a, b, others); // 1 2 (3) [3, 4, 5]
از ES2018 به بعد هم میتونیم از Spread Operator داخل ابجکت ها هم استفاده کنیم با اینکه iterable نیستن. راستی یک استفاده رایجی از Spread Operator اینه که یک ارایه رو کپی کنیم( به اصطلاح shallow copy)
const arr = ['red', 'green', 'blue']; const newArr = [...arr] console.log(newArr) // ['red', 'green', 'blue']
این دو فیچر زیاد استفاده میشن ولی یک جا که خیلی زیاد ازشون استفاده میشه مثلا داخل کتابخونه های فرم ولیدیشن مثل react hook form یا redux form هست.
خب مبحث الان Ternary Operator یا The Conditional هست. فرم کلیش به صورت زیر هست:
condition ? exprIfTrue : exprIfFalse
برخلاف Ternary Operator ،if statement یک expression هست، این باعث میشه هرجا که مجبوریم از expression استفاده کنیم بتونیم به صورت شرطی یک مقداری رو نشون بدیم مثلا داخل JSX/javascript XML که ما باهاش با جاوااسکریپت المنت میسازیم اما شبیه html هست اونجا میشه فقط از expression استفاده کرد برای مثال.
یه دلیل دیگه واسه استفاده ازش اینه که خیلی جمع و جور هست و واسه جاهایی که نیاز داریم به صورت شرطی یک کار کوچیکی رو انجام بدیم خیلی تمیز انجامش میدیم.
تو قسمت Asynchronous javascript در واقع یک کاربردش رو دیدیم
return ( <> {posts ? posts.map(post => <li key={post.id}>{post.title}</li>) : <h1>Loading</h1>} </> )
اینجا من اومدم چک کردم اگه متغیر posts فالسی ولیو نبود(null, undefined, "", NaN, false, 0) بیا روش از متود map استفاده کن و واسه هر المنت داخلش یک تگ li رو صفحه رندر کن اگه نبود هم یک تگ h1 که داخلش نوشته Loading خب همونطور که میدونیم چون گرفتن data از API، به صورت async هست و یکم زمان میبره در ابتدا چیزی نشون داده نمیشه(یه مدت زمان خیلی خیلی کمی) ولی بعد که data گرفته شد کامپوننت ها رو صفحه رندر میشن.
خب امیدوارم تا اینجا یه درک کلی داشته باشید که چیا رو باید بلد باشید. خیلی ها رو میبینم که سریع میخوان ری اکت رو شروع کنن و چون هنوز زبان رو خوب یاد نگرفتن با یادگیری ری اکت مشکل دارن. شما اگه زبان رو خوب یادبگیرید یادگیری ری اکت خیلی ساده میشه براتون. از طرفی هم افرادی رو میبینم که دانش خوبی دارن ولی انگار میترسن از شروع کردن ری اکت، برای اون دسته هم باید بگم که اگه مفاهیم بالارو درک کنید مشکلی واسه درک ری اکت نخواهید داشت.
یه سری مباحث دیگه هم هستن که باید بلد باشید ولی اون هارو اشاره نکردم به دلیل اینکه پایه مباحث این مقاله هستن و یا اینکه معمولا تو دوره ها یادشون میدن. مباحثی مثل let, const, npm و... . سعی کردم به مباحث مهم تر بپردازم. اگه سوالی هم دارید تو بخش کامنت ها بپرسید.