Professional Documents
Culture Documents
Book
Book
ریاکت React.js
جعفررضایی
️⭐ بدین .اگر هم قصد مشارکت
اگه از کتاب خوشتون اومد به گیتهابمون مراجعه کنین و بهمون
http://github.com/mariotek داشتید خیلی خوشحال میشیم 😃
فهرست
سوال ردیف
هسته ریاکت
JSXچیه؟ 3
پارامترهای keyچیکار میکنن و مزایای استفاده از اونا توی حلقهها چیه؟ 18
مفهوم lift state upیا مدیریت stateدر لول باالتر رو توضیح میدی؟ 32
contextچیه؟ 37
چرا توی کامپوننتهای کالس باید توی constructorتابع superرو با مقدار propsصدا
40
بزنیم؟
reconciliationچیه؟ 41
یه اشتباه رایج برای مدیریت توابع eventها که باعث میشه با هر رندر توابع مجدد ساخته
43
بشن چی هستش؟
تابع lazyکه برای lazy loadاستفاده میشه رو میتونیم به صورت name export
44
خروجی بگیریم؟
ReactDOMServerچیه؟ 59
چرا وقتی propها رو روی یه DOM Elemntمیآییم spreadمیکنیم باید مراقب باشیم؟ 68
چطوری باید Server-Side Renderingیا SSRرو توی ریاکت پیاده کنیم؟ 71
روش توصیه شده برای ترتیب متدها در کالس کامپوننتها چیه؟ 80
چطوری میتونیم چندتا objectاز استایلهای درون خطی رو با هم ترکیب کنیم؟ 99
روش توصیه شده برای حذف یک عنصر از آرایه توی stateچیه؟ 103
چطوری میتونیم نسخه ریاکت جاری رو توی محیط اجرایی بفهمیم؟ 110
توی CRAچطوری میشه از مسیرهای طوالنی برای ایمپورت جلوگیری کرد؟ 113
برای استایلدهیهای درون خطی چطوری باید پیشوندهای مخصوص مرورگرها رو اضافه
116
کرد؟
استثنایی که برای نامگذاری کامپوننت اجازه استفاده از حرف کوچک رو میده چیه؟ 118
چرا تابع سازنده کالس کامپوننت یکبار صدا زده میشه؟ 119
رووتر ریاکت
دلیل خطای " "Router may have only one child elementچیه؟ 135
React-Intlچیه؟ 140
Jestچیه؟ 149
React Redux
Fluxچیه؟ 152
Reduxچیه؟ 153
آیا الزمه همه stateهمه کامپوننتهامونو توی ریداکس نگهداری کنیم؟ 168
redux-sagaجیه؟ 175
React Native
Flowچیه؟ 193
Relayچیه؟ 204
متفرقه
توی PropTypeهای ریاکت چطوری میشه برای یه propچند نوع داده مجاز مشخص
213
کرد؟
الزمه همه stateها رو توی ریداکس مدیریت کنیم؟ لزومی به استفاده از stateداخلی
219
داریم؟
توی نسخه ۱۶ریاکت چطوری میشه آرایه Strings ،و یا عدد رو رندر کنیم؟ 222
مزیت چاپ شدن stack traceکامپوننتها توی متن ارور boundaryریاکت چیه؟ 234
code-splittingچیه؟ 247
چرا میگیم تابع setStateاز طریق mergeکردن stateرا مدیریت میکنه؟ 261
شرایطی که بدون مشکل پرفورمنس بتونیم از ایندکس به عنوان keyاستفاده کنیم چی
264
هست؟
گزینههای محبوب برای مدیریت فرمها توی ریاکت کدوما هستن؟ 266
چرا اجباری برای استفاده از ارثبری توی ریاکت نیست؟ مزیتی داره؟ 268
consumerچیه؟ 277
توی کامپوننتهای کنترل نشده چطوری مقداری پیش فرض اضافه کنیم؟ 293
formikچیه؟ 306
MobXچیه؟ 313
مهسا مصباح
امین آشتیانی
مهدی رحیمی
این عزیزان هر کدام با کمکهاشون برای ترجمه ،ویراستاریهاشون و حتی دلگرمیهاشون باعث شدن
این مجموعه به زبان فارسی آماده بشه و به شکل چاپی بتونه به دستان شما برسه.
ماریوتک
من جعفررضائی ،پلتفرم ماریوتک رو با هدف آموزش اصولی و رایگان ،تاسیس کردم و این کتاب هم از
مجموعه ماریوتک منتشر میشه .ما ماریوتک رو متعلق به همه میدونیم ،پس اگه بعضی تایمهای
بیکاری داری که فکر میکنی میتونی باهامون توی این مسیر همراه باشی حتما بهم ایمیل بزن
.ایدههای
ماریوتک برای افزایش آگاهی و دانش تا حد امکان رایگان خواهد بود و تا به اینجا هم ،تنها هزینههای
چاپ برداشته شده و مابقی به موسسات خیریه داده شدن.
مطالب کتاب
مطالب این کتاب میتونن تا حد بسیار خوبی دانش شما رو توی مسائل کلیدی مربوط به React.jsو
کتابخونههای پیرامون اون افزایش بدن .سواالت چالشی و کلیدی مطرح شده توی کتاب اکثرا سواالتی
هستند که توی مصاحبههای استخدامی پرسیده میشن و مسلط بودن به اونا میتونه شانس موفقیت
شما برای موقعیتهای شغلی که مدنظر دارین افزایش بده
.مطالب این کتاب به دلیل ترجمه بودن تا حد
زیادی قابل دستکاری نبودن و سعی شده تا حد امکان حق گردآورنده محفوظ باشه و با نسخه اصلی
سورس که توسط Sudheer Jonnaجمعآوری شده تفاوت معنایی نداشته باشه .بخشی از مطالب کتاب
اصلی به خاطر قدیمی بودن منقضی شده بودن و به عنوان مترجم بخشهای زیادی از نمونه کدها و
مطالب قدیمی تصحیح شدند .در آخر ،امیدوارم همیشه شاد و خندان و خوشحال باشین .مخلصیم
21
22
هسته ریاکت
.1ریاکت چیه؟
ریاکت یه کتابخونه متنباز هست که برای ساختن رابط کاربری به خصوص برنامههای تک
صفحهای استفاده میشه .از این کتابخونه برای مدیریت الیه viewتوی برنامههای وب و
موبایل استفاده میشه .توسط Jordan Walkeتولید شده که یه مهندس نرمافزار توی
شرکت فیسبوک هستش .اولین بار سال ۲۰۱۱و روی برنامه اینستاگرام مورد استفاده قرار
گرفت.
JSX .3چیه؟
23
class App extends React.Component {
render() {
return (
<div>
</div>
);
}
}
2. class component
render() {
return (
<div>
</div>
);
}
}
یک شی ساده است که وظیفه داره اون چیزی که روی صفحه نمایش داده میشهElement
هایcomponent باشه یا به صورتDOM node حاال ممکنه به صورت یک،رو توصیف کنه
ساختن. باشندprops های دیگه به عنوانElements ها میتونن شاملElement .دیگه
کار ساده و کم دردسریه اما وقتی که ساخته شد هیچ وقت نمیشهReact درElement یک
.تغییرش داد
: ساخته شده رو میبینیمReact Element تو مثال زیر یک شی که توسط
24
{
type: 'div',
{ props:
children: 'Login',
'id: 'login-btn
}
}
><div id="login-btn">Login</div
( >= )} const Button = ({ onLogin
>}<div id={"login-btn"} onClick={onLogin
Login
></div
;)
>= )} const Button = ({ onLogin
(React.createElement
"div",
{ id: "login-btn", onClick: onLogin },
""Login
;)
تو سوال قبل یه اشاره کوچیک کردیم که دوتا راه برای ساختن کامپوننت وجود داره
.
:Function Components .۱این سادهترین راه برای ساختن یه کامپوننته .یه Pure
Javascript Functionرو در نظر بگیرید که Propsکه خودش یه objectهست رو به
عنوان پارامتر ورودی میگیره و یه React Elementبه عنوان خروجی برمیگردونه مثل
همین مثال پایین:
25
{ )} function Greeting({ message
;>return <h1>{`Hello, ${message}`}</h1
}
برای اینکه ریرندر شدن یه کامپوننت رو کنترل کنیم ،توی کالس کامپوننتها بجای
Componentاز PureComponentکامپوننتمون رو میساختیم ،در حقیقت
PureComponent دقیقا مثل Component میمونه فقط تنها تفاوتی که داره اینه که
برخالف Component خودش به صورت خودکار متد shouldComponentUpdate رو
هندلمیکنه
.
وقتی که propsیا stateدر کامپوننت تغییرمیکنه PureComponent ،یه مقایسه سطحی
26
روی propsو stateانجام میده ( )shallow comparisonدر حالیکه Componentاین
مقایسه رو به صورت خودکار انجام نمیده و به طور پیشفرض کامپوننت هربار که
shouldComponentUpdate فراخوانی بشه re-renderمیشه .بنابراین توی Component
باید این متد overrideبشه
.
برای انجام اینکار روی فانکشن کامپوننتها ،میشه از React.memo استفاده کرد.
Stateدر هر کامپوننت بسته به کالس کامپوننت بودن یا فانکشن بودن نوع متفاوتی داره،
مثال در کالس کامپوننتها stateیه آبجکته که یه سری اطالعات که در طول عمر کامپوننت
ما ممکنه تغییر کنه رو در خودش ذخیرهمیکنه .ما باید تمام تالشمون رو بکنیم که
stateمون در ساده ترین حالت ممکن باشه و تاجایی که میتونیم تعداد کامپوننتهایی که
statefulهستن رو کاهش بدیم .به عنوان مثال بیایید یه کامپوننت Userرو که یه state
داره بسازیم:
1. function
{ >= )( = const User
;)'!const [message, setMessage] = useState('Hello react world
( return
><div
><h1>{message}</h1
></div
;)
}
2. class
27
{ class User extends React.Component
{ )constructor(props
;)super(props
{ = this.state
message: "Welcome to React world",
;}
}
{ )(render
( return
><div
><h1>{this.state.message}</h1
></div
;)
}
}
Stateو Propsبهم شبیه هستن ولی Stateها کامال در کنترل کامپوننت هستن و فقط
مختص به همون کامپوننت هستن( .)privateیعنی stateها در هیچ کامپوننتی به غیر از
اونی که مالک stateهست در دسترس نخواهند بود.
28
شبیه به attributeهای HTMLهست ،به کامپوننت پاس داده میشن .در واقع این مقادیر،
دادههایی هستن که از کامپوننت پدر به فرزند تحویل داده میشن.
هدف اصلی وجود Propsدر ریاکت ایجاد ساختارهای زیر در یک کامپوننتـه ،به طورکلی
میشه گفت که هدفشون:
- 1پاس دادن مقادیر به کامپوننتهای فرزند.
- 2پاس دادن متد تغییر stateو triggerکردن اون متد در زمان تغییر دلخواه.
- 3استفاده از اونا برای پاس دادن jsxو رندر کردن یه المنت دلخواه داخل یه کامپوننت
دیگه.
به عنوان مثال ،یه کامپوننت با استفاده از renderProp میسازیم:
><Element renderProp={<span>Hi there</span>} /
این ( renderProp یا هرچیز دیگهای که شما میتونین اسمشو بزارین) در نهایت تبدیل به
یک propertyخواهد شد که داخل propsورودی کامپوننت به شکل objectقابل دسترس
هست.
{ >= )const Element = (props
>return <div
}{props.renderProp
></div
}
توی کامپوننت باال یه jsxبا propبه کامپوننت Elementداده میشه و توی اون رندر میشه
😃
29
.11چرا نباید stateرو مستقیما آپدیت کنیم؟
اگه یه بار تالش کنید که مستقیما stateرو آپدیت کنید متوجه میشین که کامپوننت شما
مجددا renderنمیشه.
// Wrong
;)'let [message, setMessage] = useState('test
;"message = "Hello world
به جای اینکه مستقیما stateرو آپدیت کنیم باید از متد setStateدر Class Component
و از useStateدر Function Componentsاستفاده کنیم .این متدها یک آپدیت در شی
stateرو برنامه ریزی و مدیریت میکنن و وقتی تغییر انجام شد کامپوننت شما re-render
خواهد شد.
;)"const [message, setMessage] = React.useState("Hello world
;)"setMessage("New Hello world
توی کالس کامپوننتها میشه بعد از انجام شدن یه ،setStateیه کار خاص دیگهای رو توی
callbackانجام داد
.
callback functionزمانی که setStateتموم شد و کامپوننت مجددا renderشد فراخوانی
میشه .از اونجایی که setState به شکل asynchronousیا همون غیرهمزمان اجرا
میشه از callbackبرای کارهایی استفاده میشه که بعد از تابع setStateقراره اجرا بشن.
نکته مهم :بهتره که به جای callbackاز lifecycleمتدها استفاده کنیم.
>= )( setState({ name: "John" },
)"console.log("The name has updated and component re-rendered
;)
این سازوکار رو ،میشه روی فانکشن کامپوننتها با یه کاستوم هوک به شکل زیر پیادهسازی
کرد:
30
function useStateCallback(initialState) {
setState(state);
}, []);
useEffect(() => {
if (cbRef.current) {
cbRef.current(state);
}, [state]);
به شکل زیر.یه کم پیچیده به نظر میرسه ولی خب میتونه یه هوک خیلی کاربردی باشه
:هم ازش استفاده میکنیم
setState(
);
};
31
.13تفاوت بین نحوه مدیریت رویداد HTMLو Reactچیه؟
.1توی ،HTMLعنوان رخداد حتما باید با حرف کوچیک شروع بشه یا اصطالحا
lowercaseباشه:
><button onclick="activateLasers()"></button
><button onClick={activateLasers}>Test</button
ولی توی ریاکت برای انجام این مورد حتما باید از preventDefault استفاده بشه:
{ )function handleClick(event
;)(event.preventDefault
;)"console.log("The link was clicked.
}
.3توی HTMLبرای اجرای تابع حتما باید اونو با گذاشتن پرانتزهایی که بعد اسمش
میزاریم invokeکنیم
)(
ولی توی ریاکت اجباری به گذاشتن )( جلوی اسم تابع نیست(.برای مثال به کد
اول و تابع " "activateLasersدقت کنید)
توی کالس کامپوننتها به سه روش مختلف میتونیم thisرو به تابع هندلر موردنظرمون
bindکنیم:
Bind .1کردن توی :Constructorتوی کالسهای جاواسکریپتی متدها به صورت
پیشفرض boundنمیشن .همین موضوع توی کالس کامپوننتهای ریاکتی
برای متدهای موجود هم رخ میده که اکثرا توی متد سازنده یا همون
constructorمیآییم bindمیکنیم.
32
{ class Component extends React.Componenet
{ )constructor(props
;)super(props
;)this.handleClick = this.handleClick.bind(this
}
{ )(handleClick
//...
}
}
.2استفاده از فیلد عمومی کالس( :)publicاگه از روش اول خوشتون نمیاد این
روش هم میتونه contextدرست رو موقع callbackها براتون فراهم کنه.
{ >= )( = handleClick
;)console.log("this is:", this
;}
><button onClick={this.handleClick}>{"Click me"}</button
نکته :اگه متدهای callbackبه عنوان propبه کامپوننتهای فرزندشون پاس داده بشن،
ممکنه اون کامپوننتها re-renderingهای ناخواستهای داشته باشن .توی اینگونه موارد
روش توصیه شده استفاده از bind. یا فیلد عمومی کالس برای مدیریت پرفورمنس
هستش.
33
{ >= )const handleClick = (id
;)console.log("Hello, your ticket number is", id
;}
>= )({=return users.map(user => <button onClick
;)>handleClick(user.id)}>Test</button
جدا از این روشها ،میشه با ایجاد یه ،curryیه تابع دیگه دور تابع هندلر خودمون wrap
کنیم و پارامتر رو به اون پاس بدیم:
{ >= )( >= )const handleClick = (id
;)console.log("Hello, your ticket number is", id
;}
})return users.map(user => <button onClick={handleClick(user.id
;)>/
برای بررسی یه شرط میتونیم از عبارت شرطی ifاستفاده کنیم ،البته عملگرهای درون خطی
سهگانه( )ternaryهم میشه استفاده کرد که از ویژگیهای خود jsهستن .جدا از این
ویژگیها،میتونیم هر عبارتی داخل آکوالد و توی JSXبه اصطالح embedیا ترکیب کنیم و
با عملگر منطقی && ترکیب کنیم ،مثال پایینی رو ببنید:
34
;><h1>Hello!</h1
{
( ? messages.length > 0 && !isLogin
><h2>You have {messages.length} unread messages.</h2
( ):
><h2>You don't have unread messages.</h2
;)
}
مواقعی که یه آیدی خاص برای المانها نداریم ،ممکنه بیایید و از اندیس یا همون index
به عنوان keyاستفاده کنید:
( >= )const todoItems = todos.map((todo, index
><li key={index}>{todo.text}</li
;))
نکته:
.1استفاده از indexها برای keyتوصیه نمیشه چون ممکنه ترتیب عناصر خیلی
راحت عوض بشه و این میتونه پرفورمنس برنامه رو تحت تاثیر بزاره.
.2اگه بیایین و لیست مورد نظر رو به جای li مثال با یه کامپوننت به اسم
ListItemجایگزین کنین و propموردنظر keyرو به جای li به اون پاس
بدیم ،یه warningتوی کنسول خواهیم داشت که میگه keyپاس داده نشده.
35
.19کاربرد refها چیه؟
refبه عنوان یه مرجع برای دسترسی مستقیم به ِالمان موردنظرمون استفاده میشه .تا حد
امکان و توی اکثر مواقع بهتره از اونا استفاده نکنیم ،البته خیلی میتونن کمک کننده باشن
چون دسترسی مستقیمی به DOM elementیا instanceاصلی componentبهمون
میدن.
{ >= )( = const Component
;)(const myRef = React.createRef
;>return <div ref={myRef} /
;}
{ >= )( = const RenderCounter
;)const counter = useRef(0
// Since the ref value is updated in the render phase,
// the value can be incremented more than once
;counter.current = counter.current + 1
}return <h1>{`The component has been re-rendered ${counter
;>times`}</h1
;}
36
const ButtonElement = React.forwardRef((props, ref) => (
{props.children}
</button>
));
componentDidMount() {
findDOMNode(this).scrollIntoView();
render() {
return <div></div>;
}
}
useEffect(() => {
nodeRef.current.scrollIntoView();
}, []);
37
.23چرا Refهای متنی منقضی محسوب میشوند؟
اگه قبال با ریاکت کار کرده باشین ،احتمال با یه APIقدیمی تر آشنا هستین که توی اون
ویژگی refیه رشتهست ،مثل 'ref='textInput و DOMبه صورت
refs.textInput قابل دسترسیـه .البته این ویژگی توی نسخه ۱۶ریاکت حذف شده و
توصیه نمیشه استفاده بشه ،فقط برای یادگیری هست.
.1ریاکت رو مجبور میکنن که عناصر در حال اجرا رو دنبال کنه و این مساله یکم
مشکل سازه چون باعث میشه خطاهای عجیب و غریب وقتی که ماژول
ریاکت باندل میشه ،رخ بده.
.2قابل انعطاف نیستن .اگه یه کتابخونه خارجی یه refرو روی فرزند قرار بده،
کاربر نمیتونه یه refدیگهای رو روی اون اضافه کنه.
.3با یه آنالیزگر استاتیک مثل Flowکار نمیکنه و در حقیقت Flowیا
تایپاسکریپت نمیتونه حدس بزنه که فریمورک چه کاری روی ref انجام
میده ،مثل نوع داده اون(که ممکنه متفاوت باشه)ref .های callbackدار بیشتر
با آنالیزگرها سازگارترن.
.4اون طور که اکثر مردم از الگوی " "render callbackانتظار دارن کار نمی
کنه(برای مثال ) >/ }DataGrid renderRow={this.renderRow<
{ class MyComponent extends Component
{ >= )renderRow = (index
// This won't work. Ref will get attached to DataTable
rather than MyComponent:
;>return <input ref={"input-" + index} /
// This would work though! Callback refs are awesome.
= ]return <input ref={(input) => (this["input-" + index
;>input)} /
;}
{ )(render
=return <DataTable data={this.props.data} renderRow
;>{this.renderRow} /
}
}
)Virtual DOM(VDOMیه کپی داخل memoryاز DOMواقعی هستش .این کپی از
المانهای رابط کاربری توی حافظه رم نگهداری میشه و همواره با DOMاصلی و واقعی
38
همگام سازی( )syncمیشه .این مرحله بین تابع رندر و نمایش elementها روی صفحه رخ
میده و به مجموعه اتفاقاتی که برای مدیریت این موارد انجام میشه reconciliationمیگن.
.3بعد از انجام محاسبات DOM ،واقعی فقط با مواردی که واقعًا تغییر کردن به
روز میشه.
39
.26تفاوت بین Shadow DOMو Virtual DOMچیه؟
shadow DOMیه تکنولوژی مرورگره که در ابتدا برای تعیین متغیرها و ایزولهسازی css
دروب کامپوننت( )Web componentطراحی شده بود virtual DOM .مفهومیه که توسط
کتابخونهها برای مدیریت DOMتوسط جاواسکریپت با استفاده از APIهای مرورگرها اجرا
شده.
40
.28هدف اصلی React Fiberچیه؟
هدف پیادهسازی ReactFiberبرای بهبود کارکرد توی ناحیههایی مثل انیمیشن،layout ،
کار با gestureها بود .میشه گفت مهمترین ویژگی incremental-renderingبوده که
قابلیت بخشبندی( chunkکردن) عملیات اجرایی و متوقف و اجرا کردن اون توی فریمهای
مختلف هست.
کامپوننتی که عناصر ورودی رو توی فرمهای ورودی کاربر کنترلمیکنه به عنوان کامپوننت
کنترل شده شناخته میشن ،توی این کامپوننتها هر تغییر stateیه تابع نگهدارنده مرتبط
باهاش رو داره.
به عنوان مثال ،اگر یه inputداشته باشیم و بخواییم اسم فرد رو بگیریم و به شکل حروف
بزرگ نگهداری کنیم ،باید از handleChangeمثل زیر استفاده کنیم:
;)''(const [name, setName] = useState
{ >= )const handleChange = (event
;))(setName(event.target.value.toUpperCase
}
>return <input value={name} onChange={handleChange} /
41
{ >= )( = const UserProfile
;)(const inputRef = useRef
{ >= )const handleSubmit = (event
;)alert("A name was submitted: " + inputRef.current.value
;)(event.preventDefault
}
( return
>}<form onSubmit={handleSubmit
><label
}"{"Name:
><input type="text" ref={input} /
></label
><input type="submit" value="Submit" /
></form
;)
}
اکثر مواقع ،توصیه میشه که از کامپوننتهای کنترلشده بجای این روش برای پیادهسازی
فرمها و دریافت داده استفاده کنیم.
.32مفهوم lift state upیا مدیریت stateدر لول باالتر رو توضیح میدی؟
وقتی که کامپوننتهای مختلف نیاز به یه داده خاص دارن که بین اونا مشترکه بهتره
stateهای مشترک رو تا حد امکان به نزدیکترین کامپوننت باالییشون انتقال بدیم .این
مورد به این معنیه که اگه دو کامپوننت فرزند داریم که یه stateمشخص رو دارن مدیریت
میکنن توی خودشون ،اون stateرو میبریم توی کامپوننت والد و بجای مدیریت یه state
توی دوتا کامپوننت ،از یه جا و توی کامپوننت والد اون رو مدیریت میکنیم.
42
.33فازهای مختلف از lifecycleکامپوننت کدوما هستن؟
43
قبل از ورژن ۱۶.۳
44
:componentDidMountبعد از اولین رندر اجرا میشه و همه درخواستهای
AJAX، DOMیا بروزرسانی stateو تنظیمات event listenersاجرا میشه.
:shouldComponentUpdateتعیینمیکنه که کامپوننت به روز بشه یا نه.
به طور پیش فرض مقدار true رو برمیگردونه .اگه مطمئن باشیم که
کامپوننت بعد از اینکه stateیا propsبه روزرسانی میشه نیازی به رندر شدن
نداره ،میتونیم مقدار false رو برگردونیم .اینجا جای خوبی برای بهبود
عملکرده چون این امکان رو بهمون میده که اگه کامپوننت propجدید میگیره
از renderمجدد جلوگیری کنیم.
:getSnapshotBeforeUpdateدرست قبل از رندر مجدد خروجی به DOM
اجرا میشه .هر مقداری که توسط این متد برگشت داده میشه به متد
componentDidUpdate انتقال داده میشه .برای گرفتن اطالعات از موقعیت
اسکرول DOMمفیده.
:componentDidUpdateبیشتر برای به روزرسانی DOMدر پاسخ به تغییرات
stateیا Propاستفاده میشه .این متد زمانی که
shouldComponentUpdate مقدار false رو برگردونه قابل استفاده ست.
componentWillUnmountاین متد برای کنسل کردن همه درخواستهای
شبکه خروجی یا حذف همهevent listenerهای مرتبط با کامپوننت استفاده
میشه.
قبل ورژن ۱۶.۳
:componentWillMountقبل از رندر اجرا میشه و برای پیکربندی سطح
برنامه توی کامپوننت ریشه استفاده میشه.
:componentDidMountبعد از اولین رندر اجرا میشه و همه درخواستهای
AJAX، DOMیا بروزرسانی stateو تنظیمات event listenersاجرا میشه.
componentWillReceiveProps: Executed when particular prop
.updates to trigger state transitions
:shouldComponentUpdateتعیینمیکنه که کامپوننت به روز بشه یا نه.
به طور پیش فرض مقدار true رو برمیگردونه .اگه مطمئن باشیم که
کامپوننت بعد از اینکه stateیا propsبه روزرسانی میشه نیازی به رندر شدن
نداره ،میتونیم مقدار false رو برگردونیم .اینجا جای خوبی برای بهبود
عملکرده چون این امکان رو بهمون میده که اگه کامپوننت propجدید میگیره
از renderمجدد جلوگیری کنیم.
:componentWillUpdateقبل از رندر مجدد کامپوننت وقتی که تغییرات
stateو propsتوسط shouldComponentUpdate مقدار true رو
برگردونده باشه اجرا میشه.
45
:componentDidUpdateبیشتر برای به روزرسانی DOMدر پاسخ به تغییرات
stateیا Propاستفاده میشه .این متد زمانی که
shouldComponentUpdate مقدار false رو برگردونه قابل استفاده ست.
componentWillUnmountاین متد برای کنسل کردن همه درخواستهای
شبکه خروجی یا حذف همهevent listenerهای مرتبط با کامپوننت استفاده
میشه.
= const EnhancedComponent
;)higherOrderComponent(WrappedComponent
46
{ )function HOC(WrappedComponent
{ return class Test extends Component
{ )(render
{ = const newProps
title: "New Header",
footer: false,
showFeatureX: false,
showFeatureY: true,
;}
}return <WrappedComponent {...this.props} {...newProps
;>/
}
;}
}
context .37چیه؟
Contextروشی رو برای انتقال داده بین کامپوننتها فراهممیکنه بدون اینکه بخوایم توی
هر سطح به صورت دستی دادهها رو منتقل کنیم .به عنوان مثال ،معتبر بودن کاربر ،چند
زبانگی و فایلهای زبان ،قالب UIمواردی هستن که توی خیلی از کامپوننتها و به شکل
عمومی الزم داریم که در دسترس باشن و میتونیم از contextبرای مدیریتشون استفاده
کنیم.
47
. میشه React.Children.toArray
. این پایین نوشته شدهchildren prop یه مثال ساده از استفاده از
render: function () {
return <div>{this.props.children}</div>;
},
});
ReactDOM.render(
<MyDiv>
<span>{"Hello"}</span>
<span>{"World"}</span>
</MyDiv>,
node
);
شبیه به جاواسکریپت هستن اما کامنتهای چند خطی تویReact/JSX کامنتها توی
.آکوالد قرار میگیرن
:کامنتهای تک خطی
<div>
</div>
<div>
</div>
48
رو باsuper تابعconstructor چرا توی کامپوننتهای کالس باید توی.40
صدا بزنیم؟props مقدار
استفاده this صدا زده نشده نمیتونه از super تا زمانی که متدconstructor کالس
دلیل اصلی انتقال. هم صدق میکنهES6 همین مورد در رابطه با کالسهای.کنه
توی this.props دسترسی داشتن به super به متد فراخوانprops پارامترهای
. هستشconstructor
:props با پاس دادن
constructor(props) {
super(props);
}
}
constructor(props) {
super();
render() {
}
}
متفاوت عمل میکنه وconstructor فقط توی this.props کد باال نشون میده که
هنوز، دلیلش هم اینه که توی متد سازنده کالس، عملکردش عادیهconstructor بیرون از
. کامل ساخته نشده و در حال ساخته شدنهinstance
49
reconciliation .41چیه؟
وقتی stateیا propsیه کامپوننت تغییرمیکنه ،ریاکت با مقایسه عنصر تازه returnشده
و نمونه renderشده قبلی تصمیم میگیره که به روزرسانی DOMواقعا ضروریه یا نه .وقتی
این دو مقدار با هم برابر نباشه ،ریاکت به روزرسانی DOMرو انجام میده .به این فرایند
reconciliationگفته میشه.
اگر برای تبدیل کد JSXاز ES6یا babelاستفاده میکنین میتونید این کار رو با
computed property namesانجام بدین.
{ )handleInputChange(event
)} this.setState({ [event.target.id]: event.target.value
}
اینجا ما یه فیلد از Objectرو به شکل متغیر داریم پر میکنیم ،البته روی فانکشن
کامپوننتها و با استفاده از هوک useStateهم میشه به شکل داینامیک یه objectرو پر
کرد و فقط الزمه یه stateبه شکل objectداشته باشیم:
;)(const [myState, setMyState] = useState
{ >= )const handleInputChange = (event
;)} setMyState({ [event.target.id]: event.target.value
}
.43یه اشتباه رایج برای مدیریت توابع eventها که باعث میشه با هر رندر
توابع مجدد ساخته بشن چی هستش؟
باید مطمئن باشیم که موقع استفاده از تابع هندلرمون به عنوان پارامتر ،اون تابع صدا زده
نشه .مثال:
50
!// Correct: handleClick is passed as a reference
>return <button onClick={this.handleClick}>{'Click Me'}</button
// MoreComponents.js
;export const SomeComponent = /*... */
;export const UnusedComponent = /*... */
// IntermediateComponent.js
;"export { SomeComponent as default } from "./MoreComponents.js
حاال میتونیم ماژول خودمون رو با استفاده از تابع lazyبه شکل زیر importکنیم.
;"import React, { lazy } from "react
>= )((const SomeComponent = lazy
;))"import("./IntermediateComponent.js
class یه کلمه کلیدی توی جاواسکریپتـه و فایل با پسوند JSXدر حقیقت همون فایل
جاواسکریپتـه .دلیل اصلی استفاده ریاکت از className به جای class همینه و یه
مقدار رشتهای رو به عنوان پارامتر className پاس میدیم .مثل کد زیر:
51
{ )(render
>return <span className='menu navigation-menu'>Menu</span
}
یه الگوی مشخص توی ریاکت وجود داره که برای کامپوننتهایی استفاده میشه که چندین
عنصر یا کامپوننت رو برمیگردونن_Fragment_ .ها این امکان رو فراهم میکنن که بتونیم
لیستی از فرزندان رو بدون اضافه کردن نودهای اضافی به DOMگروه بندی کنیم.
{ )(render
( return
><React.Fragment
><ChildA /
><ChildB /
><ChildC /
></React.Fragment
)
}
{ )(render
( return
><
><ChildA /
><ChildB /
><ChildC /
></
)
}
البته میدونیم که نه فقط divبلکه از بقیه تگهای htmlهم میشه بجای fragment
استفاده کرد ولی به دالیل زیر بهتره از fragmentاستفاده بشه:
Fragment.1ها یه کم سریعترن و با ایجاد نکردن DOM nodeاضافی حافظه
کمتری استفاده میکنن .این فقط روی nodeهای بزرگ و درختهای بزرگ و
52
عمیق مزیت داره.
.2بعضی از مکانیزمهای CSSمثل Flexboxو CSS Gridروابط والد و فرزندی
خاصی دارند و اضافه کردن divدر وسط ،حفظ طرح مورد نظرمون را
دشوارمیکنه.
DOM Inspector .3بهم ریختگی کمتری داره و میشه راحتتر کدهای برنامه رو
دیباگ کرد.
Portalروشی توصیه شده برای رندر کردن کامپوننت فرزند به شکل DOMو خارج از سلسله
مراتب DOMکامپوننت والد هستش.
;)ReactDOM.createPortal(child, container
اولین آرگومان یه فرزند قابل رندر شدن هستش ،مثل عنصر ،رشته ،یا .fragmentآرگومان
دوم عنصر DOMهستش.
.49کامپوننت statelessچیه؟
اگه رفتار یه کامپوننت مستقل از stateاون کامپوننت باشه بهش کامپوننت stateless
گفته میشه .میتونیم از یه تابع یا یه کالس برای ساخت کامپوننتهای statelessاستفاده
کنیم،
.50کامپوننت statefulچیه؟
اگه رفتار یه کامپوننتی به stateاون کامپوننت وابسته باشه ،به عنوان کامپوننت statefull
شناخته میشه.
53
{ >= )( = const App
;)const [count, setCount] = useState(0
( return
//...
;)
}
{ class App extends Component
{ )constructor(props
;)super(props
;} this.state = { count: 0
}
{ )(render
// ...
}
}
وقتی برنامه توی حالت developmentیا در حال توسعه هست ،ریاکت به شکل خودکار
تمام propهایی که ما توی کامپوننت استفاده کردیم رو چک میکنه تا مطمئن بشه
همهشون نوع درستی دارن .اگه هر کدوم از propها typeدرستی نداشته باشن توی کنسول
بهمون یه warningنشون میده ،البته توی حالت productionاین حالت غیر فعاله
.
propهای اجباری با پراپرتی isRequiredمشخص میشن ،همچنین یهسری انواع propاز
پیش تعریف شده وجود دارن که میتونیم ازشون استفاده کنیم:
PropTypes.number .1
PropTypes.string .2
PropTypes.array .3
PropTypes.object .4
PropTypes.func .5
54
PropTypes.node .6
PropTypes.element .7
PropTypes.bool .8
PropTypes.symbol .9
PropTypes.any .10
return (
<>
<h1>{`Welcome, ${props.name}`}</h1>
<h2>{`Age, ${props.age}`}</h2>
</>
);
User.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number.isRequired,
};
چیه؟React مزایای.52
55
.53محدودیتهای Reactچیه؟
Error boundaryها یا به اصطالح تحت الفظی مرزهای خطا کامپوننتهایی هستن که
خطاهای جاواسکریپت رو هرجایی توی درخت فرزنداش رخ داده باشن catchمیکنن و
خطای موردنظر رو logمیکنن و عالوه براین میتونن یه UIبه اصطالح fallbackرو بجای
کامپوننت crashشده نشون بدن.
توی یه کالس کامپوننت با گذاشتن متد )componentDidCatch(error, info یا
static getDerivedStateFromError میتونیم یه boundaryبرای زمانی که خطایی
رخ میده درست کنیم .مثل:
56
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
componentDidCatch(error, info) {
logErrorToMyService(error, info);
static getDerivedStateFromError(error) {
render() {
if (this.state.hasError) {
return this.props.children;
}
}
<ErrorBoundary>
<MyWidget />
</ErrorBoundary>
57
.56روشهای پیشنهادی برای type checkingچیه؟
به طور معمول به دو روش میشه نوع propورودی در برنامههای ریاکتی رو چک کرد .روش
اول استفاده از کتابخانه prop-typesو اعتبارسنجی ورودیهای کامپوننتـه و روش دوم که
برای برنامههایی با کدهای بیشتر توصیه میشه ،استفاده از __static type checkerهایی
مثل flowیا typeScriptهست که چک کردن نوع داده رو در زمان توسعه و کامپایل انجام
میده ویژگیهای مثل auto-completionرو ارائه میده.
این متد برای رندرکردن کامپوننت پاس داده شده ،توی یه المنت DOMکه به عنوان
containerپاس داده شده ،استفاده میشه و یه رفرنس به کامپوننت برمیگردونه .اگه
کامپوننت ریاکت قبال توی containerمورد نظر رندر شده باشه با یه updateفقط
DOMهایی که نیازمند به روز شدن باشن رو ری-رندر میکنه.
)]ReactDOM.render(element, container[, callback
اگه پارامتر سوم که یه callbackهست پاس داده بشه ،هر موقع که رندر یا بهروزرسانی
انجام بشه اون تابع هم اجرا میشه.
58
ReactDOMServer .59چیه؟
// using Express
;"import { renderToString } from "react-dom/server
;"import MyPage from "./MyPage
{ >= )app.get("/", (req, res
(res.write
>"<!DOCTYPE html><html><head><title>My Page</title></head
"><body
;)
;)'>"res.write('<div id="content
;))>res.write(renderToString(<MyPage /
;)">res.write("</div></body></html
;)(res.end
;)}
59
function
{ )(createMarkup
return
;} "{ __html: "First · Second
}
function
{ )(MyComponent
return
;><div dangerouslySetInnerHTML={createMarkup()} /
}
{ = const divStyle
color: "blue",
backgroundImage: "url(" + imgUrl + ")",
;}
{ )(function HelloWorldComponent
;>return <div style={divStyle}>Hello World!</div
}
مدیریت رویدادها روی ِالمانهای ریاکت یه سری تفاوتهای کلی با نحوه مدیریت اونا روی
jsداره:
event handler.1های ریاکت یه جای حروف کوچیک به صورت حروف بزرگ
نامگذاری میشن.
.2با JSXما یه تابع رو به جای رشته به عنوان event handlerپاس میدیم.
گ
60
.63اگه توی constructorبیاییم و setStateکنیم چی میشه؟
keyها باید پایدار ،قابل پیش بینی و منحصر به فرد باشن تا ریاکت بتونه ِالمانها رو
رهگیری کنه
.
تو کد زیر keyهر عنصر براساس ترتیبی که توی لیست داره مقدار قرار می گیره و به
دادههایی که میگیرن ربطی نداره .این کار بهینه سازیهایی که میتونه توسط ریاکت انجام
بشه رو محدود میکنه.
;)>todos.map((todo, index) => <Todo {...todo} key={index} /
اگه از دادههای همون elementبه عنوان کلید بخوایم استفاده کنیم ،مثال .todo.idچونکه
همه ویژگیهایی که یه کلید باید داشته باشه رو داره ،هم استیبله و هم منحصر به فرد،
توی این حالت ریاکت میتونه بدون اینکه الزم باشه دوباره همه ِالمنتها رو ارزیابی کنه
رندر رو انجام بده.
;)>todos.map((todo) => <Todo {...todo} key={todo.id} /
61
componentDidMount که اگه مقدار دهی اولیه غیر همزمانای داریم این کار رو توی متد
. componentWillMount انجام بدیم نه در متد
componentDidMount() {
axios.get(`api/todos`)
.then((result) => {
this.setState({
messages: [...result.data]
})
})
useEffect(() => {
axios.get(`api/todos`)
.then((result) => {
setMessages([...result.data])
})
}, []);
مقدار جدید اون،های یه کامپوننت بدون اینکه اون کامپوننت رفرش بشه تغییر کنهpropاگه
مقدار، جاری اون کامپوننت رو به روز رسانی نمیکنهstate نمایش داده نمیشه چونprop
.ها فقط زمانی که کامپوننت برای بار اول ساخته شده اجرا میشهprop ازstate دهی اولیه
:کامپوننت زیر مقدار به روزرسانی شده رو نشون نمیده
constructor(props) {
super(props);
this.state = {
records: [],
inputValue: this.props.inputValue,
};
render() {
return <div>{this.state.inputValue}</div>;
}
}
62
و نکته جالبش اینه که استفاده ازpropها توی متد renderمقدار رو به روز رسانیمیکنه:
{ class MyComponent extends React.Component
{ )constructor(props
;)super(props
{ = this.state
record: [],
;}
}
{ )(render
;>return <div>{this.props.inputValue}</div
}
}
توی فانکشن کامپوننتها هم دقیقا به همین شکل هست ،مقدار اولیه useStateاگه از
propورودی کامپوننت باشه ،با تغییر دادن propمقدار اون stateعوض نمیشه ،دلیلش
هم اینه که هوک useStateفقط توی اولین رندر اجرا میشه و بعدش دیگه باید با استفاده
از متد setterاش مقدار اون stateرو عوض کنیم.
بعضی وقتا ما می خوایم کامپوننتهای مختلفی رو بسته به بعضیstateها رندر کنیمJSX .
مقدار false یا undefined رو رندر نمیکنه ،بنابراین ما میتونیم از short-circuiting
شرطی برای رندر کردن بخش مشخصی از کامپوننتمون استفاده کنیم در صورتی که اون
شرط مقدار trueرو برگردونده باشه.
( >= )} const MyComponent = ({ name, address
><div
><h2>{name}</h2
}>{address && <p>{address}</p
></div
;)
63
( >= )} const MyComponent = ({ name, address
><div
><h2>{name}</h2
{address ? <p>{address}</p>: <p>{"Address is not
}>available"}</p
></div
;)
( >= )( = const ComponentA
><ComponentB isDisplay={true} className={"componentStyle"} /
;)
( >= )} const ComponentB = ({ isDisplay,...domProps
><div {...domProps}>{"ComponentB"}</div
;)
میتونیم کالس کامپوننت ها رو decorateکنیم ،که درست مثل پاس دادن کامپوننتها به
تابع هستشDecorator.ها روش قابل خواندن و انعطاف پذیرتری برای تغییر فانکشنالیتی
کامپوننتها هستن.
64
@setTitle("Profile")
//....
/*
*/
document.title = title;
render() {
};
};
ولی توی، اضافه نشدنES7 ها ویژگیهایی هستن که در حال حاضر بهDecorator :نکته
. هستنstage 2 پیشنهاد
کردن ایجاد شدن و میتوننmemoize در حال حاضر کتابخانههایی وجود داره که با هدف
میتونه یه moize به عنوان مثال کتابخونه،توی کامپوننتهای تابع استفاده بشن
. کنهmemoize کامپوننت رو توی بقیه کامپوننتها
65
import moize from "moize";
<div>
<MemoizedFoo />
</div>;
};
});
// OR
ReactDOMServer.renderToString(<App />);
صفحه بهbody معمولی به صورت یه رشتهست که داخلHTML خروجی این روش یه
. سرور قرار میگیرهresponse عنوان
ریاکت محتوای از قبل رندر شده رو تشخیص میده و به صورت فرآیند،در سمت کاربر
.)rehydration(همگامسازی با اونا رو انجام میده
66
.72چطوری حالت productionرو برای ریاکت فعال کنیم؟
میشه از پالگین DefinePlugin که روی وبپک قابل استفاده هست استفاده کرد و
مقدار NODE_ENV رو روی production ستکرد ،با اینکار خطاهای اضافی یا اعتبارسنجی
propTypeها روی پروداکشن غیرفعال میشه و جدای این موارد ،کدهای نوشته شده
بهینهسازی میشن و مثال کدهای بالاستفاده حذف میشن ،کم حجمسازی انجام میشه و
درنتیجه سرعت بهتری رو میتوته به برنامه بده چون سایز bundleایجاد شده کوچیکتر
خواهد بود.
# Installation
$ npm install -g create-react-app
# Create new project
$ create-react-app todo-app
$ cd todo-app
# Build, test and run
$ npm run build
$ npm run test
$ npm start
این شامل همه اون چیزیه که ما واسه ساختن یه برنامه ریاکت الزم داریم:
React، JSX، ES6 .1و روند پشتیبانی .syntax
.2موارد اضافی زبان شامل ES6و عملگر object spreadو اینا.
،Autoprefixed CSS .3بنابراین نیازی به -webkit-یا پیشوندهای دیگهای
نداریم.
.4یه اجرا کننده تست تعاملی با پشتیبانی داخلی برای .coveraage reporting
.5یه سرور live developmentکه اشتباهات معمول رو بهمون هشدار میده.
.6یه اسکریپت بیلد برای پک و باندل کردن css، jsو تصاویر برای production
همراه باhashها و sourcemapها.
67
.74ترتیب اجرا شدن متدهای life cycleچطوریه؟
بعد از اینکه یه کامپوننت بالفاصله بدون خطا و مثل قبل rerenderشد ،متد استاتیک
getDerivedStateFromProps صدا زده میشه
.
این متد یا stateآپدیت شده رو به صورت یه آبجکت برمی گردونه یا nullرو برمی گردونه که
معنیش اینهpropهای جدید به آپدیت شدن stateنیازی ندارن.
{ class MyComponent extends React.Component
{ )static getDerivedStateFromProps(props, state
//...
}
}
68
.77کاربرد متد getSnapshotBeforeUpdateچیه؟
{ class MyComponent extends React.Component
{ )getSnapshotBeforeUpdate(prevProps, prevState
//...
}
}
برای نام گذاری کامپوننتها توصیه میشه که از نامگذاری هنگام exportگرفتن به جای
displayName استفاده کنیم .استفاده از displayName برای نام گذاری کامپوننت:
{(export default React.createClass
displayName: "TodoApp",
//...
;)}
;)( >= )( = const TodoApp
;export default TodoApp
69
.80روش توصیه شده برای ترتیب متدها در کالس کامپوننتها چیه؟
70
import HomePage from "./HomePage";
const PAGES = {
home: HomePage,
about: AboutPage,
services: ServicesPage,
contact: ContactPage,
};
};
// The keys of the PAGES object can be used in the prop types
to catch dev-time errors.
Page.propTypes = {
page: PropTypes.oneOf(Object.keys(PAGES)).isRequired,
};
. یا ناهمزمانهasync یه عملیات setState دلیلش اینه که
ممکنه بالفاصله بعدstate بنابراین یه،ها در ریاکت به دالیل عملکردی تغییر میکننstate
. صدا زده شد تغییر نکنه setState
از اینکه
جاری اعتماد کنیم چونstate رو صدا می زنیم نباید به setState یعنی اینکه وقتی
. چی میتونه باشهstate نمیتونیم مطمئن باشیم که اون
. پاس بدیم setState قبلی به عنوان یه آرگومان بهstate راه حلش اینه که یه تابع رو با
مقدار، بعد از سه عملیات پشت هم. صفر هستشcount بیاین فرض کنیم مقدار اولیه
. فقط یکی افزایش پیدا میکنهcount
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
71
اگه ما یه تابع به setState پاس بدیم ،مقدار countبه درستی افزایش پیدا میکنه.
{( >= )this.setState((prevState, props
count: prevState.count + props.increment,
;))}
// this.state.count === 3 as expected
;"import React from "react
{ )(function ExampleApplication
( return
><div
><Header /
><React.StrictMode
><div
><ComponentOne /
><ComponentTwo /
></div
></React.StrictMode
><Footer /
></div
;)
}
__Mixinها روشی برای جدا کردن کامپوننتهایی با عملکرد مشترک بودن .با توسعه یافتن
ریاکت دیگهMixinها نباید استفاده بشن و میتونن با کامپوننتهای با اولویت باال()HOC
72
یا __decoratorها جایگزین بشن.
یکی از بیشترین کاربردهایmixinها PureRenderMixin بود .ممکنه تو بعضی از
کامپوننتها برای جلوگیری ازre-renderهای غیر ضروری وقتیpropها و stateبا مقادیر
قبلی شون برابر هستن از اینmixinها استفاده کنیم:
نکته مهمmixin :های ریاکت منقضی شدن و دیگه کاربردی ندارن ،این سوال فقط برای
افزایش آگاهی توی کتاب باقی میمونه.
{ ))(if (this.isMounted
)}this.setState({...
}
دلیل اینکه این روش توصیه نمیشه اینه که خطایی رو که ریاکت بهمون میداد رو داره دور
میزنه و حلش نمیکنه .بهتره setStateرو جایی انجام بدیم که توی مواقعی که کامپوننت
mountنیست اجرا نشه.
البته توی نسخههای جدید ریاکت این کار رو خیلی سادهتر میشه انجام داد و فقط کافیه یه
هوکی بنویسیم که یه refرو مقداردهی میکنه و بعد با بررسی اون refمیشه فهمید که
کامپوننت mountشده یا نه ،مثال:
73
{ >= )( = export const useIsMounted
;)const componentIsMounted = useRef(true
(useEffect
{ >= )( >= )(
;componentIsMounted.current = false
},
][
;)
;return componentIsMounted
;}
یا حتی یه پکیجی ساخته شده به اسم ismounted که میتونه بهمون کمک کنه که
متوجه بشیم کامپوننت mountشده یا نه .ولی حواسمون باشه که ازش درست استفاده
کنیم.
__pointer Eventها یه روش واحدی رو برای هندل کردن همه ی ایونتهای ورودی ارائه
میدن
.
در زمانهای قدیم ما از موس استفاده میکردیم و برای هندل کردن ایونتهای مربوط به اون
ازevent listenerها استفاده میکردیم ولی امروزه دستگاههای زیادی داریم که با داشتن
موس ارتباطی ندارن ،مثل قلمها یا گوشیهای صفحه لمسی
.
باید یادمون باشه که این ایونتها فقط تو مرورگرهایی کار میکنن که مشخصه Pointer
Eventsرو پشتیبانی میکنن.
ایونتهای زیر در React DOMدر دسترس هستن:
onPointerDown .1
onPointerMove .2
onPointerUp .3
onPointerCancel .4
onGotPointerCapture .5
onLostPointerCapture .6
onPointerEnter .7
onPointerLeave .8
onPointerOver .9
onPointerOut .10
گ
74
.87چرا باید اسم کامپوننت با حرف بزرگ شروع بشه؟
اگه ما با استفاده از JSXکامپوننتمون رو رندر میکنیم ،اسم کامپوننت باید با حرف بزرگ
شروع بشه در غیر این صورت ریاکت خطای تگ غیر قابل تشخیص رو میده
.
این قرارداد به خاطر اینه که فقط عناصر HTMLو تگهای svgمی تونن با حرف کوچیک
شروع بشن
.
class SomeComponent extends Component
{
Code goes here //
}
میتونیم کالس کامپوننتهایی که با حرف کوچیک شروع میشن رو هم تعریف کنیم ولی وقتی
داریم ایمپورت میکنیم باید شامل حروف بزرگ هم باشن:
{ class myComponent extends Component
{ )(render
;>return <div /
}
}
;export default myComponent
وقتی داریم تو یه فایل دیگهای ایمپورت میکنیم باید با حرف بزرگ شروع بشه:
;"import MyComponent from "./MyComponent
بله .اون قدیما ریاکتDOM attributeهای ناشناخته رو نادیده میگرفت ،اگه JSXرو با یه
ویژگیای نوشته بودیم که ریاکت تشخیص نمیداد ،اونو نادیده میگرفت .به عنوان مثال:
><div mycustomattribute="something" /
><div /
><div mycustomattribute="something" /
75
این برایattributeهای غیر استاندارد مرورگرهای خاصDOM API،های جدید و ادغام با
کتابخانههای third-partyمفیده.
{ class MyComponent extends React.Component
{ )constructor(props
;)super(props
{ = this.state
/* initial state */
;}
}
}
استفاده از : React.createClass
{(const MyComponent = React.createClass
{ )(getInitialState
{ return
/* initial state */
;}
},
;)}
نکته React.createClass :در ورژن 16ریاکت حذف شده و به جای اون میشه از
کالسهای ساده جاواسکریپت استفاده کرد.
در حالت پیش فرض ،وقتی stateیا propکامپوننت تغییر میکنه ،کامپوننت دوباره رندر
میشه .اگه متد render به دادههای دیگهای وابسته باشه ،توی فانکشن کامپوننتها
میتونیم یه stateتعریف کنیم و با ست کردن یه مقدار جدید توی اون stateعامدانه باعث
رندر مجدد کامپوننت بشیم .مثل:
76
const [tick, setTick] = useState(0);
میتونیم انتظار رندر شدن،توی مثال باال ما یه تابع تولید کردیم که با هر بار فراخوانی اون
.کامپوننت رو داشته باشیم
به ریاکت بگیم که این forceUpdate میتونیم با فراخوانی متد،توی کالس کامپوننتها
.کامپوننت نیازه که دوباره رندر بشه
component.forceUpdate(callback);
constructor(props) {
super(props);
}
}
constructor(props) {
super();
console.log(this.props); // undefined
}
}
77
.92چطوری توی JSXحلقه یا همون لوپ رو داشته باشیم؟
><tbody
( >= ){items.map((item
><SomeComponent key={item.id} name={item.name} /
}))
></tbody
><tbody
{ )for (let i = 0; i < items.length; i++
><SomeComponent key={items[i].id} name={items[i].name} /
}
></tbody
به خاطر اینکه تگهای JSXداخل function callsتبدیل میشن ما نمیتونیم از
statementها داخل عبارات استفاده کنیم.
><img className="image" src="images/{this.props.image}" /
اما ما میتونیم هر عبارت jsرو داخل کرلی براکت( ) }{ به عنوان مقدار کلی attributeقرار
بدیم
.
مثال ،تکه کد پایین کارمیکنه:
><img className="image" src={"images/" + props.image} /
><img className="image" src={`images/${this.props.image}`} /
78
داشتهshape ها باobject برایآرایهای ازPropType چطوری یه.94
باشیم؟
از،اگه بخوایم آرایهای از آبجکتها رو به یه کامپوننت با شکل خاصی پاس بدیم
React.PropTypes.arrayOf به عنوان یه آرگومان برای React.PropTypes.shape
.استفاده میکنیم
ReactComponent.propTypes = {
arrayWithShape: React.PropTypes.arrayOf(
React.PropTypes.shape({
color: React.PropTypes.string.isRequired,
fontSize: React.PropTypes.number.isRequired,
})
).isRequired,
};
) استفاده کنیم چون به عنوان یه رشته در '' () داخل کوتیشن }{ (نباید از کرلی براکت
.نظر گرفته میشه
بینspace (فراموش نکنیم که از.به جاش میتونیم کرلی بریس رو به بیرون انتقال بدیم
).ها استفاده کنیمclassName
79
.96تفاوتهای Reactو ReactDOMچیه؟
تیم ریاکت سعی کرده تمام ویژگیهای مرتبط با DOMرو جدا کنه و اونا رو توی یه کتابخونه
جدا به اسم ReactDomقرار بده .ریاکت ورژن ۱۴اولین نسخهای بود که توش این
کتابخونهها از هم جدا شدن .با یه نگاه به بعضی از پکیجهای ریاکت مثل
react-native ، react-art ، react-canvas و react-three مشخص میشه
که زیبایی و جوهر ریاکت هیچ ربطی به مرورگرها یا DOMنداره .برای ساختن محیطهای
بیشتری که ریاکت بتونه رندر بشه ،تیم ریاکت اومد و پکیج اصلی ریاکت رو به دو بخش
تقسیم کنه react :و
. react-dom
از این طریق تونست کامپوننتهایی تولید کنه بین ریاکت وب و ریاکت نیتیو و ...قابل
اشتراک باشه.
اگه سعی کنیم که با استفاده از for attributeیه عنصر >label< متصل به یه متن رو
رندر کنیم ،اون وقت ویژگی HTMLبودن رو از دست میده و یه خطا توی کنسول بهمون
نشون میده.
><label for={'user'}>{'User'}</label
><input type={'text'} id={'user'} /
از اونجایی که for یه کلمه کلیدی رزرو شده توی جاواسکریپته ،به جاش باید از
htmlFor استفاده کنیم.
80
><label htmlFor={'user'}>{'User'}</label
><input type={'text'} id={'user'} /
=<button style
>}} {{...styles.panel.button,...styles.panel.submitButton
}"{"Submit
></button
اگه داریم از ریکت نیتیو استفاده میکنیم میتونیم از شکل آرایهای استایلها استفاده کنیم:
<button style={[styles.panel.button,
>}]styles.panel.submitButton
}"{"Submit
></button
81
class WindowDimensions extends React.Component {
constructor(props) {
super(props);
this.updateDimensions = this.updateDimensions.bind(this);
componentWillMount() {
this.updateDimensions();
componentDidMount() {
window.addEventListener("resize", this.updateDimensions);
componentWillUnmount() {
window.removeEventListener("resize",
this.updateDimensions);
updateDimensions() {
this.setState({
width: window.innerWidth,
height: window.innerHeight,
});
render() {
return (
<span>
{this.state.width} x {this.state.height}
</span>
);
}
}
همین کار رو با استفاده از هوکها هم میشه انجام داد و برای این کار همین کد رو توی
. مینویسیم useEffect
82
const [dimensions, setDimensions] = useState();
useEffect(() => {
window.addEventListener("resize", updateDimensions);
function updateDimensions() {
setDimensions({
width: window.innerWidth,
height: window.innerHeight,
});
return () => {
window.removeEventListener("resize", updateDimensions);
};
}, []);
return (
<span>
{this.state.width} x {this.state.height}
</span>
);
مقادیر فعلی و قبلی، روی کالس کامپوننت استفاده میکنیم setState وقتی که از متد
ای که میخواییمstate حالت فعلی رو با replaceState .با هم ترکیب میشن
همه، برای جایگزین کردن استفاده کنیم setState معموال اگه از.جایگزینش میکنه
با استفاده از replaceState البته میشه بجای استفاده از.کلیدهای قبلی رو پاک کنیم
. قرار بدیم null یا false رو برابر باstate بیاییم و setState
با. یه سری متدها فراخوانی میشهstate توی کالس کامپوننتها هنگام به روز شدن
فعلی رو با مقادیر جدید مقایسه کرده و یه سریprop وstate استفاده از این متدها میشه
.کار که مدنظر داریم رو انجام بدیم
83
با استفاده از هوک useEffectهم این امکان بسادگی قابل انجامه و فقط کافیه به
dependencyهای این هوک متغیر مربوط به stateرو بدیم.
;)(const [someState, setSomeState] = useState
{ >= )((useEffect
// code
;)]}, [someState
{ )removeItem(index
{(this.setState
)data: this.state.data.filter((item, i) => i !== index
)}
}
توی نسخههای باالتر از (>= )16.2میشه .برای مثال تکه کد پایین یه سری مثال برای رندر
کردن یه مقدار غیر htmlای هست:
{ )(render
return false
}
{ )(render
return null
}
{ )(render
][ return
}
84
{ )(render
>return <React.Fragment></React.Fragment
}
{ )(render
>return <></
}
;} const data = { name: "John", age: 42
{ class User extends React.Component
{ )(render
;>return <pre>{JSON.stringify(data, null, 2)}</pre
}
}
;))"React.render(<User />, document.getElementById("container
فلسفه ساختاری ریاکت به شکلیه که propها باید immutableباشن و از باال به پایین و به
صورت سلسهمراتبی مقدار بگیرند .به این معنی که پدر هر کامپوننت میتونه هر مقداری رو
به فرزند پاس بده و فرزند حق دستکاری اونو نداره.
85
فوکوس کنیم؟input چطوری میتونیم موقع لود صفحه روی یه.107
useEffect(() => {
nameInputRef.current.focus();
}, []);
return (
<div>
</div>
);
};
componentDidMount() {
this.nameInput.focus();
render() {
return (
<div>
defaultValue={"Will focus"}
/>
</div>
);
}
}
86
استفاده از Object.assign برای ایجاد یه کپی از :object
;)} const user = Object.assign({}, this.state.user, { age: 42
;)} this.setState({ user
;} const user = {...this.state.user, age: 42
;)} this.setState({ user
{( >= )this.setState((prevState
{ user:
...prevState.user,
age: 42,
},
;))}
ریاکت اجازه ترکیب کردن تغییرات stateرو با استفاده از متد setState فراهم کرده،
همین موضوع باعث بهبود پرفورمنس میشه .توی کالس کامپوننتها this.props و
this.state ممکنه به صورت asynchronousو همزمان به روز بشن ،نباید به مقدار
اونا برای محاسبه مقدار بعدی اعتماد کرد.
برای مثال به این شمارنده که درست کار نمیکنه دقت کنیم:
// Wrong
{(this.setState
counter: this.state.counter + this.props.increment,
;)}
روش توصیه شده فراخوانی متد setState با یه تابع بجای objectهست .این تابع
مقدار stateقبلی رو به عنوان پارامتر اول و propرو به عنوان ورودی دوم میگیره و این
تابع رو زمانی که مقادیر ورودیش تغییر پیدا کنن فراخوانی میکنه.
// Correct
{( >= )this.setState((prevState, props
counter: prevState.counter + props.increment,
;))}
87
چطوری میتونیم نسخه ریاکت جاری رو توی محیط اجرایی بفهمیم؟.110
. برای گرفتن نسخه جاری استفاده کرد React.version خیلی ساده میشه از مقدار
ReactDOM.render(
document.getElementById("app")
);
import "core-js/fn/array/find";
import "core-js/fn/array/includes";
import "core-js/fn/number/is-nan";
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?
features=default,Array.prototype.includes"></script>
88
.112توی CRAچطوری از httpsبهجای httpاستفاده کنیم؟
برای اینکار الزمه که کانفیگ HTTPS=true رو برای envجاریست کنیم ،برای اینکار
حتی الزم هم نیست فایل env.بسازیم و میتونیم توی فایل package.json بخش
scriptsرو به شکل پایین تغییر بدیم:
{ "scripts":
""start": "set HTTPS=true && react-scripts start
}
یا حتی به شکل set HTTPS=true && npm start هم میشه تغییر داد.
NODE_PATH=src/app
بعد از این تغییر سرور developرو ریستارت میکنیم بعدش دیگه میتونیم هر چیزی رو از
مسیر src/app بارگذاری کنیم و الزم هم نباشه مسیر کاملشو بهش بدیم .اینکار رو
میشه با بخش module resolveتوی webpackهم انجام داد.
یه listenerبه آبجکت history اضافه میکنیم تا بتونیم لود شدن صفحه رو track
کنیم:
{ )history.listen(function (location
window.ga("set", "page", location.pathname +
;)location.search
window.ga("send", "pageview", location.pathname +
;)location.search
;)}
89
برداشته شده تاhistory دسترسی مستقیم بهreact-router-dom از۶ توی نسخه
به شکل زیرuseLocation توی این نسخه میشه از، راحتتر باشهsuspense پشتیبانی از
:استفاده کرد
useEffect(() => {
}, [location]);
useEffect(() => {
return () => {
clearInterval(intervalRef.current);
}, [location]);
componentDidMount() {
componentWillUnmount() {
clearInterval(this.interval)
90
.116برای استایلدهیهای درون خطی چطوری باید پیشوندهای مخصوص
مرورگرها رو اضافه کرد؟
ریاکت به شکل اتوماتیک پیشوندهای مخصوص مرورگرها روی cssرو اعمال نمیکنه.
الزمه که تغییرات رو به شکل دستی اضافه کنیم.
<div
{{=style
transform: "rotate(90deg)",
'WebkitTransform: "rotate(90deg)", // note the capital 'W
here
msTransform: "rotate(90deg)", // 'ms' is the only lowercase
vendor prefix
}}
>/
;"import React from "react
;"import User from "user
{ export default class MyProfile extends React.Component
{ )(render
;>return <User type="customer">//...</User
}
}
گ
91
.118استثنایی که برای نامگذاری کامپوننت اجازه استفاده از حرف کوچک رو
میده چیه؟
همه کامپوننتهای ریاکت الزمه که با حرف بزرگ شروع بشن ،ولی توی این مورد هم یه
سری استثناها وجود داره .تگهایی که با propertyو عملگر dotکار میکنن رو میشه به
عنوان کامپوننتهایی با حرف کوچک تلقی کرد .برای مثال این تگ میتونه syntaxمعتبری
برای ریاکت باشه که با حروف کوچیک شروع میشه:
{ >= )( = const Component
( return
<obj.component /> //
`)`React.createElement(obj.component
)
}
{ class MyComponent extends React.Component
;static DEFAULT_PAGINATION = 10
}
92
.121چطوری توی برنامه eventکلیک شدن رو triggerکنیم؟
><input ref={inputRef} /
;)(inputRef.click
93
common/
├─ Avatar.js
├─ Avatar.css
├─ APIUtils.js
└─ APIUtils.test.js
feed/
├─ index.js
├─ Feed.js
├─ Feed.css
├─ FeedStory.js
├─ FeedStory.test.js
└─ FeedAPI.js
profile/
├─ index.js
├─ Profile.js
├─ ProfileHeader.js
├─ ProfileHeader.css
└─ ProfileAPI.js
api/
├─ APIUtils.js
├─ APIUtils.test.js
├─ ProfileAPI.js
└─ UserAPI.js
components/
├─ Avatar.js
├─ Avatar.css
├─ Feed.js
├─ Feed.css
├─ FeedStory.js
├─ FeedStory.test.js
├─ Profile.js
├─ ProfileHeader.js
└─ ProfileHeader.css
94
.124پکیجهای مشهور برای انیمیشن کدوما هستن؟
خیلی توصیه میشه که از استایلدهیهای سخت و مستقیم برای کامپوننتها پرهیز کنیم.
هرمقداری که فقط در یک کامپوننت خاصی مورد استفاده قرار میگیره ،بهتره که درون
همون فایل لود بشه.
برای مثال ،این استایلها میتونن تو یه فایل دیگه انتقال پیدا کنن:
{ = export const colors
white,
black,
blue,
;}
;]export const space = [0, 8, 16, 32, 64
;"import { space, colors } from "./styles
ESLintیه linterبرای JavaScriptهستش .یه سری کتابخونه برای کمک به کدنویسی تو
سبکهای مشخص و استاندارد برای eslintوجود داره .یکی از معروفترین پالگینهای
موجود eslint-plugin-react هست
.
به صورت پیشفرض این پالگین یه سری از best practiceها رو برای کدهای نوشته شده
بررسی میکنه و یه مجموعه از قوانین رو برای کدنویسی الزام میکنه .پالگین مشهور دیگه
eslint-plugin-jsx-a11y هستش ،که برای بررسی نکات و ملزومات معروف در زمینه
accessibilityکمک میکنه .چرا که JSXیه سینتکس متفاوتتری از HTMLارائه میکنه،
مشکالتی که ممکنه مثال با alt و tabindex پیش میاد رو با این پالگین میشه متوجه
شد.
95
بزنیم؟api call چطوری باید توی کامپوننت درخواست.127
useEffect(() => {
fetch("https://api.example.com/items")
.then(
(result) => {
setEmployees(result.employees);
},
(error) => {
setError(error);
);
}, []);
return error ? (
<div>Error: {error.message}</div>
): (
<ul>
{employees.map((employee) => (
<li key={employee.name}>
{employee.name}-{employee.experience}
</li>
))}
</ul>
);
};
96
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
employees: [],
error: null,
};
componentDidMount() {
fetch("https://api.example.com/items")
.then(
(result) => {
this.setState({
employees: result.employees,
});
},
(error) => {
);
render() {
if (error) {
} else {
return (
<ul>
{employees.map((employee) => (
<li key={employee.name}>
{employee.name}-{employee.experience}
</li>
))}
</ul>
);
}
}
97
render props .128چیه؟
Render Propsیه تکنیک ساده برای به اشتراک گذاری کامپوننت بین کامپوننتهای
دیگهـست که با استفاده از یه propکه یه تابع یا یه کامپوننت رو بهش دادیم انجام میشه.
کامپوننت زیر از همین روش برای پاس دادن یه React elementاستفاده میکنه و توی
کامپوننت پایین این propرو یه شکل یه تابع فراخوانی میکنیم و چون یه تابع هست،
میتونیم بهش هر مقداری که میخواییم بیاریم این سمت رو پاس بدیم.
React Router
React Routerیه کتابخونه قدرتمند برای جابجایی سریع بین صفحات و flowهای مختلفه
که برپایه ریاکت نوشته شده و امکان syncکردن آدرس وارد شده با صفحات رو توی
محیطهای مختلف فراهم میکنه.
98
.131کامپوننتهای routerتوی نسخه ۴کدوما هستن؟
روشهای مختلفی برای جابجایی در برنامه و توسط کد وجود داره که پایین لیست میکنیم،
ولی روش آخر(استفاده از هوکها) بهترین و سادهترین روش توی کامپوننتهای تابعی
هست.
.1استفاده از تابع مرتبه باالتر(: higher-order) withRouter
متد withRouter آبجکت historyرو به عنوان یه propبه کامپوننت اضافه
میکنه .روی این propبه متدهای push و replace دسترسی داریم که
بهسادگی میتونه مسیریابی بین routeها رو فراهم کنه و نیاز به contextرو
رفع کنه.
99
import { withRouter } from "react-router-dom"; // this also
works with 'react-router-native'
<button
type="button"
onClick={() => {
history.push("/new-location");
}}
>
{"Click Me!"}
</button>
));
<Route
<button
type="button"
onClick={() => {
history.push("/new-location");
}}
>
{"Click Me!"}
</button>
)}
/>
);
100
const Button = (props, context) => (
<button
type="button"
onClick={() => {
context.history.push("/new-location");
}}
>
{"Click Me!"}
</button>
);
Button.contextTypes = {
history: React.PropTypes.shape({
push: React.PropTypes.func.isRequired,
}),
};
return (
<button
type="button"
onClick={() => {
history.push("/new-location");
}}
>
{"Click Me!"}
</button>
);
};
:۶ نسخه
101
const Page = (props, context) => {
const navigate = useNavigate();
return (
<button
type="button"
onClick={() => {
navigate("/new-location");
}}
>
{"Click Me!"}
</button>
);
};
. هستuseParams های آدرس استفاده از هوکparam سادهترین راه برای دسترسی به
" چیه؟Router may have only one child element" دلیل خطای.135
102
><Router
><Switch
><Route {/*... */} /
><Route {/*... */} /
></Switch
></Router
{(this.props.history.push
pathname: "/template",
search: "?name=sudheer",
state: { detail: response.data },
;)}
این کانفیگها یکیش searchهست که میتونه پارامتر موردنظر ما رو به مسیر مورد نظر
بفرسته.
><Switch
><Route exact path="/" component={Home} /
><Route path="/user" component={User} /
><Route component={NotFound} /
></Switch
گ
103
.138توی ریاکت روتر نسخه ۴چطوری میشه historyرو گرفت؟
;"import { createBrowserHistory } from "history
{(export default createBrowserHistory
/* pass a configuration object here if needed */
;)}
;"import { Router } from "react-router-dom
;"import history from "./history
;"import App from "./App
(ReactDOM.render
>}<Router history={history
><App /
</Router>,
holder
;)
// some-other-file.js
;"import history from "./history
;)"history.push("/go-here
نکته :روی نسخه ۶دسترسی مستقیم به historyحذف شده و برای هر کار یه هوک
مختص به اون کار مهیا شده.
104
;"import React, { Component } from "react
;"import { Redirect } from "react-router
{ >= )( = const Component
{ )if (isLoggedIn === true
;>return <Redirect to="/your/redirect/page" /
{ } else
;>return <div>{"Login Please"}</div
}
}
چندزبانگی ریاکت
React-Intl .140چیه؟
React Intlیه کتابخونه برای آسان نمودن توسعه برنامههای چند زبانهـست .این کتابخونه
از مجموعهای از کامپوننتها و APIها برای فرمتبندی رشتهها ،تاریخ و اعداد رو برای
سادهسازی فرآیند چندزبانگی فراهم میکنه React Intl .بخشی از FormatJSهست که
امکان اتصال به ریاکت رو با کامپوننتهای خودش فراهم میکنه.
105
.142دو روش فرمت کردن توی React Intlکدوما هستن؟
این کتابخونه از دو روش برای فرمتبندی رشتهها ،اعداد و تاریخ استفاده میکنه:
کامپوننتهای ریاکتی و .API
<FormattedMessage
}"id={"account
}"defaultMessage={"The amount is less than minimum balance.
>/
{(const messages = defineMessages
{ accountMessage:
id: "account",
defaultMessage: "The amount is less than minimum balance.",
},
;)}
;)formatMessage(messages.accountMessage
106
import React from "react";
};
MyComponent.propTypes = {
intl: intlShape.isRequired,
};
);
MyComponent.propTypes = {
intl: intlShape.isRequired,
};
107
import { injectIntl, intlShape } from "react-intl";
year: "numeric",
month: "numeric",
day: "numeric",
});
);
MyComponent.propTypes = {
intl: intlShape.isRequired,
};
تست ریاکت
این روش بهمون. برای نوشتن یونیت تست توی ریاکت کاربرد دارهShallow rendering
این امکان رو میده که به عمق یک مرتبه کامپوننت موردنظرمون رو رندر کنیم و مقدار
. ارزیابی کنیم،بازگردانی شده رو بدون اینکه نگران عملکرد کامپوننتهای فرزند باشیم
: اگه کامپوننتی به شکل زیر داشته باشیم،برای مثال
function MyComponent() {
return (
<div>
<span className={"heading"}>{"Title"}</span>
<span className={"description"}>{"Description"}</span>
</div>
);
108
:میتونیم انتظار اجرا به شکل پایین رو داشته باشیم
// in your test
renderer.render(<MyComponent />);
expect(result.type).toBe("div");
expect(result.props.children).toEqual([
<span className={"heading"}>{"Title"}</span>,
<span className={"description"}>{"Description"}</span>,
]);
معرفی میکنه که میتونیم ازش برای رندر کردن کامپوننتها وrenderer این پکیج یه
یاDOM استفاده کنیم بدون اینکه وابستگی بهpure JavaScript تبدیل اونا به یه آبجکت
از سلسله مرتبsnapshot این پکیج برای گرفتن.محیط اجرایی موبایلی داشته باشیم
درستReact Native یاReactDOM ) که توسطDOM (یه چیزی شبیه به درختview
. فراهم میکنه jsdom میشه رو بدون نیاز به مرورگر یا
<Link page={"https://www.facebook.com/"}>{"Facebook"}</Link>
);
console.log(testRenderer.toJSON());
// {
// type: 'a',
// children: [ 'Facebook' ]
// }
109
.148هدف از پکیج ReactTestUtilsچیه؟
Jest .149چیه؟
Jestیه فریمورک برای یونیت تست کردن جاواسکریپت هستش که توسط فیس بوک و
براساس Jasmineساخته شده Jest .امکان ایجاد اتوماتیک (mockدیتا یا مقدار ثابت
برای تست) و محیط jsdom رو فراهم میکنه.
خب بیایین یه تست برای تابعی که جمع دو عدد رو توی فایل sum.js برامون انجام میده
بنویسیم:
110
;"import sum from "./sum
{ >= )( test("adds 1 + 2 to equal 3",
;)expect(sum(1, 2)).toBe(3
;)}
{
{ "scripts":
""test": "jest
}
}
در آخر ،دستور yarn test یا npm test اجرا میکنیم و Jestنتیجه تست رو برامون
چاپ میکنه:
$ yarn test
PASS./sum.test.js
)✓ adds 1 + 2 to equal 3 (2ms
React Redux
Flux .152چیه؟
Fluxیه الگوی طراحی برنامهـست که به عنوان جایگزینی برای اکثر پترنهای MVCسنتی به
کار میره .در حقیقت یه کتابخونه یا فریمورک نیست و یه معماری برای تکمیل کارکرد ریاکت
با مفهوم جریان داده یک طرفه( )Unidirectional Data Flowبه کار میره .فیسبوک از این
پترن به شکل داخلی برای توسعه ریاکت بهره میگیره.
جریان کار بینdispatcher، storeها و viewهای کامپوننتها با ورودی و خروجی مشخص
به شکل صفحه بعد خواهد بود:
111
Redux .153چیه؟
112
.155کاستیهای reduxنسبت به fluxکدوما هستن؟
بجای گفتن کاستیها بیایین مواردی که میدونیم موقع استفاده از Reduxبجای Flux
داریم رو بگیم:
.1باید یاد بگیریم که mutationانجام ندیم Flux :در مورد mutateکردن داده
نظری نمیدهد ،ولی Reduxاز mutateکردن داده جلوگیری میکنه و
پکیجهای مکمل زیادی برای مطمئن شدن از mutateنشدن stateتوسط
برنامهنویس ایجاد شدهاند .این مورد رو میشه فقط برای محیط توسعه با
پکیجی مثل redux-immutable-state-invariant ، Immutable.js یا
آموزش تیم برای نوشتن کد بدون mutateدیتا محقق کرد.
.2باید توی انتخاب پکیجها محتاطانه عمل کنید Flux :به شکل خاص کاری برای
حل مشکالتی مثل undo/redo، persistکردن داده یا مدیریت فرمها انجام
نداده است .در عوض Reduxکلی middlewareو مکمل storeبرای محقق
ساختن همچین نیازهای داره.
.3شاید هنوز یه جریان داده خوشگل نداشته باشه در حال حاضر Fluxبهمون
اجازه یه type checkاستاتیک خوب رو میده ولی Reduxهنوز پشتیبانی
خوبی نداره براش.
{ >= )const mapStateToProps = (state
{ return
todos: getVisibleTodos(state.todos,
state.visibilityFilter),
;}
;}
113
{ >= )const mapDispatchToProps = (dispatch
{ return
{ >= )onTodoClick: (id
;))dispatch(toggleTodo(id
},
;}
;}
{ = const mapDispatchToProps
onTodoClick,
;}
و البته هوکهای ریداکس برای دسترسی به stateو انجام actionمورد نظر هم خیلی
کاربرد داره.
Dispatchکردن actionتوی reducerیه آنتی پترن محسوب میشه reducer .نباید هیچ
سایدافکتی داشته باشه ،فقط باید خیلی ساده stateقبلی و actionفعلی رو بگیره و state
جدید رو بده .اینکار رو اگه با افزودن یه سری listenersو dispatchکردن با تغییرات
reducerهم انجام بدیم باز باعث ایجاد actionهای تودرتو میشه و میتونه ساید افکت
داشته باشه،
114
;)const store = createStore(myReducer
;export default store
این دو کتابخونه خیلی متفاوتن و برای اهداف متفاوتی استفاده میشن ،ولی یه سری
تشابههای ریزی دارن.
Reduxیه ابزار برای مدیریت stateتوی کل برنامهست .اکثرا هم به عنوان یه معماری برای
ایجاد رابط کاربری استفاده میشه RxJS .یه کتابخونه برای برنامهنویسی (reactiveکنش گرا)
هستش .اکثرا هم برای انجام تسکهای asynchronousتوی جاواسکریپت به کار میره.
میتونیم بهش به عنوان یه معماری بجای Promiseنگاه کنیم Redux .هم از الگوی
Reactiveاستفاده میکنه چون Storeریداکس reactiveهستش Store .میاد actionها
رو از دور میبینه و تغییرات الزم رو توی خودش ایجاد میکنه RxJS .هم از الگوی Reactive
پیروی میکنه ،ولی بجای اینکه خودش این architectureرو بسازه میاد به شما یه سری
بالکهای سازنده به اسم Observableمیده که باهاش بتونید الگوی reactiveرو اجرا کنید
.
خیلی ساده میشه اون actionرو موقع mount اجرا کرد و موقع render دیتای مورد نیاز
رو داشت.
115
const App = (props) => {
useEffect(() => {
props.fetchData();
}, []);
return props.isLoaded ? (
<div>{"Loaded"}</div>
): (
<div>{"Not Loaded"}</div>
);
};
isLoaded: state.isLoaded,
});
:برای دسترسی به دیتای نگهداری شده توی ریداکس باید دو گام زیر رو طی کنیم
store که ازstate استفاده میکنیم و متغیرهای mapStateToProps از متد.1
.میخواییم لود کنیم رو مشخص میکنیم
چون دیتایی که این، میدیمprops دیتا رو بهconnect با استفاده از متد.2
رو هم connect متد. به کامپوننت داده میشهprops میاره به عنوانHOC
. باید بارگذاری کنیم react-redux از پکیج
116
import React from 'react';
render() {
return <div>{props.containerData}</div>
}
};
};
تعریف کنیم که وظیفه معرفی ریدیوسرهای ایجادroot reducer الزمه که توی برنامه یه
. را دارد combineReducers شده با
اولیه با فراخوانی عملstate رو برای ست کردن rootReducer مثال بیایین
به صورت پیشفرض ما بنا رو براین، همونطوری که میدونیم. تنظیم کنیم USER_LOGOUT
روinitialState به عنوان پارامتر اول undefined ها با اجرای مقدارreducer میزاریم که
.ش هم مهم نیستaction برمیگردونن و حتی
});
state = undefined;
};
117
const appReducer = combineReducers({
});
Object.keys(state).forEach((key) => {
storage.removeItem(`persist:${key}`);
});
state = undefined;
};
118
import React from "react";
function mapStateToProps(state) {
function mapDispatchToProps(dispatch) {
:decorator با
function mapStateToProps(state) {
function mapDispatchToProps(dispatch) {
@connect(mapStateToProps, mapDispatchToProps)
ها استفاده میکنه وdecorator مثالهای باال تقریبا شبیه به هم هستن فقط یکیشون از
هنوز به صورت پیشفرض توی هیچکدوم ازdecorator سینتکس.اون یکی حالت عادیه
های جاواسکریپت فعال وجود نداره و هنوز به شکل آزمایشی مورد استفاده قرارruntime
119
میگیره ولی پروپوزال افزوده شدنش به زبان در دست بررسیه .خوشبختانه فعال میتونیم از
babelبرای استفاده از اون استفاده کنیم.
120
{ )export function fetchAccount(id
{ >= )return (dispatch
dispatch(setLoadingAccountState()); // Show a loading
spinner
{ >= )fetch(`/account/${id}`, (response
dispatch(doneFetchingAccount()); // Hide loading spinner
{ )if (response.status === 200
dispatch(setAccount(response.json)); // Use a normal
function to set the received state
{ } else
;)dispatch(someError
}
;)}
;}
}
{ )function setAccount(data
;} return { type: "SET_Account", data: data
}
بهترین روش ،بسته به هر پروژه و هر فرد میتونه متفاوت باشه ،ترجیح من استفاده از
هوکهای useSelectorو useDispatchهستن ،برای دسترسی به storeو انجام عملیات
روی اون استفاده از تابع connect هم میتونیم استفاده کنیم که یه کامپوننت جدید
ایجاد میکنه که کامپوننت جاری توی اون قرار داره و دیتای الزم رو بهش پاس میده .این
پترن با عنوان Higher-Order Componentsیا کامپوننتهای مرتبه باالتر شناخته میشه و
یه روش مورد استفاده برای extendکردن کارکرد کامپوننتهای ریاکتی محسوب میشه.
این تابع بهمون این امکان رو میده که stateو actionهای مورد نظرمون رو به داخل
کامپوننت بیاریم و البته به شکل پیوسته با تغییرات اونا کامپوننتمون رو به روز کنیم.
بیایین یه مثال از کامپوننت >FilterLink< با استفاده از تابع connectبزنیم:
121
;"import { connect } from "react-redux
;"import { setVisibilityFilter } from "../actions
;"import Link from "../components/Link
{( >= )const mapStateToProps = (state, ownProps
active: ownProps.filter === state.visibilityFilter,
;)}
{( >= )const mapDispatchToProps = (dispatch, ownProps
>= )( onClick:
dispatch(setVisibilityFilter(ownProps.filter)),
;)}
)const FilterLink = connect(mapStateToProps, mapDispatchToProps
;)(Link
;export default FilterLink
Constantها یا موارد ثابت بهتون این اجازه رو میدن که کارکرد یه عملکرد مشخص رو به
سادگی توی پروژه پیدا کنید .البته از خطاهای سادهای که ممکنه براتون پیش بیاد هم
122
ها که ممکنه خیلی ReferenceError یاtype مثل خطاهای مربوط به.جلوگیری میکنه
.راحت رخ بدن
یا constants.js ( رو توی یه فایل مثلconstant اکثرا مقادیر ثابت
.) قرار میدیم actionTypes.js
:هاreducer توی.2
: رو در نظر بگیرین reducer.js مثال یه فایل به اسم
switch (action.type) {
case ADD_TODO:
return [
...state,
text: action.text,
completed: false,
},
];
default:
return state;
}
};
123
چیه؟mapDispatchToProps روشهای مختلف برای نوشتن.172
});
});
124
{
;"user: "john
}
میتونیم از این مقدار استفاده کنیم تا در مورد مقدار بازگشتی تصمیم بگیریم.
redux-saga .175جیه؟
$ npm install --save redux-saga
125
.176مدل ذهنی redux-sagaچطوریه؟
Sagaمثل یه threadجداگانه برای برنامه عمل میکنه و فقط برای مدیریت ساید افکت
کارایی داره redux-saga .یه میانافزار( )middlewaerبرای ریداکسـه ،که به معنی اینه
که میتونه به صورت اتوماتیک توسط actionهای ریداکس شروع بشه ،متوقف بشه و یا کار
خاصی انجام بده .این میانافزار به کل storeریداکس و actionهایی که کار میکنن
دسترسی داره و میتونه هر actionدیگهای رو dispatchکنه.
هر دوی افکتهای call و put سازندههای افکت هستن .تابع call برای ایجاد
توضیح افکت استفاده میشه که به میانافزار دستور میده منتظر callبمونه .تابع put یه
افکت ایجاد میکنه ،که به storeمیگه یه actionخاص رو فقط اجرا کنه.
بزارین یه مثال در مورد عملکرد این دوتا افکت برای دریافت داده یه کاربر بزنیم.
{ )function* fetchUserSaga(action
// `call` function accepts rest arguments, which will be
passed to `api.fetchUser` function.
// Instructing middleware to call promise, it resolved value
will be assigned to `userData` variable
;)const userData = yield call(api.fetchUser, action.userId
// Instructing middleware to dispatch corresponding action.
{(yield put
type: "FETCH_USER_SUCCESS",
userData,
;)}
}
میان افزار Redux Thunkبهمون این اجازه رو میده که actionهایی رو بسازیم که بهجای
ع برگردونن thunkمیتونه به عنوان یه ایجاد کننده delayبرای dispatch
actionعادی تاب
کردن یه actionاستفاده کنیم ،یا حتی با بررسی یه شرط خاص یه actionرو dispatch
کنیم .تابعی که توی actionاستفاده میشه و dispatch و getState رو به عنوان
پارامتر ورودی میگیره.
126
.179تفاوتهای redux-sagaو redux-thunkچیا هستن؟
127
.182سلکتورهای ریداکس چی هستن و چرا باید ازشون استفاده کنیم؟
;const getUserData = (state) => state.user.data
ReduxFormدر کنار ریاکت و ریداکس کار میکنه تا اطالعات فرمها رو توی state
ریداکس مدیریت کنیم ReduxForm .میتونه با inputهای خام HTML5هم کار کنه ،ولی با
فریمورکهای معروف UIمثل Material، ReactWidgetsو ReactBootstrapکار کنه.
;"import { createStore, applyMiddleware } from "redux
(const createStoreWithMiddleware = applyMiddleware
ReduxThunk,
logger
;))(createStore
128
.186چطوری میشه توی ریداکس initial stateتعریف کرد؟
{(const rootReducer = combineReducers
todos: todos,
visibilityFilter: visibilityFilter,
;)}
{ = const initialState
todos: [{ id: 123, name: "example", completed: false }],
;}
;)const store = createStore(rootReducer, initialState
Relayو Reduxتوی این مورد که دوتاشونم از یه storeاستفاده میکنن شبیه بهم هستن.
تفاوت اصلی این دو اینه که relayفقط stateهایی رو مدیریت میکنه که از سرور تاثیر
گرفتن و همه دسترسیهایی که به stateمربوطه رو با کوئریهای (GraphQLبرای خوندن
دادهها) و mutationها (برای تغییرات داده) انجام میده Relay .دادهها برای شما رو cache
میکنه و گرفتن داده از سرور رو برای شما بهینه میکنه .چون فقط تغییرات رو دریافت
میکرد و نه چیز دیگهای.
React Native
129
React Nativeیه فریمورک موبایل هست که کدها رو به کامپوننتهای
nativeروی موبایل compileمیکنه و بهمون این اجازه رو میده که برنامههای
موبایلی( )iOS, Android, and Windowsرو با استفاده از جاواسکریپت
بسازیم که از ریاکت برای تولید کامپوننت استفاده میکنه.
$ react-native log-ios
$ react-native log-android
130
کتابخونههای ریاکت و Integrationهاشون
Flow .193چیه؟
Flowیه static type checkerهستش که طراحی شده تا خطاهای مربوط به نوع دادهها
رو توی جاواسکریپت پیدا کنیم .نوعهای flowمیتونه خیلی ریزبینانهتر از رویکردهای سنتی
بررسی نوع عمل کنه .برای مثال Flow ،بهمون کمک میکنه که خطاهای مربوط به دریافت
null توی برنامه رو کنترل کنیم که توی روشهای سنتی غیرممکنه تقریبا.
131
کنه .پس اگه دنبال یه روش برای بررسی نوع داده به شکل منعطف هستیم که توی کل
پروژه عمل کنه Flowیا TypeScriptروشهای بهتری هستن.
به شکل کلی ،باید cssو فونت آیکون مربوط به font-awesomeبه پروژه اضافه بشه،
میتونیم از پکیج این کتابخونه روی npmاستفاده کنیم و بگیم که باید گامهای زیر برای
استفاده از font-awesomeتوی ریاکت باید طی بشه:
.1پکیج font-awesome رو نصب میکنیم:
npm install --save font-awesome
;"import "font-awesome/css/font-awesome.min.css
{ )(render
>return <div><i className={'fa fa-spinner'} /></div
}
132
لود نمیشه؟local برای فایلهایdevtools چرا توی کروم.197
) بعدش الزمه که ...//:file ( رو توی مرورگر باز کنیمHTML اگه یه فایل محلی
یا همون افزونههای کروم رو باز کنیم و چکباکسChromeExtensions
. رو فعال کنیم Allow access to file URLs
<link rel="import"
href="../../bower_components/polymer/polymer.html" />;
Polymer({
is: "calender-element",
ready: function () {
},
});
<link
rel="import"
href="./src/polymer-components/calender-element.html"
/>
render() {
}
}
133
.199مزایای Reactنسبت به Vue.jsکدوما هستن؟
Angular React
در Angularجریان دادهها از دو جهته ،یعنی در ریاکت جریان دادهها فقط از یه
اتصال دادههای دوطرفه بین والدین و طریق( )one-directionalهستش و
فرزندان رو داره و به خاطر همین اشکال به همین خاطر اشکال زدایی()debug
زدایی سخت تره راحت تره
نکته :لیست موارد فوق صرفًا اظهار نظر شخصی بوده و براساس تجربه حرفهای ممکن است
متفاوت باشد .اما به عنوان پارامترهای پایه مفید هستند
.
134
چیه؟Styled components .202
font-size: 1.5em;
text-align: center;
color: palevioletred;
padding: 4em;
background: papayawhip;
<Wrapper>
</Wrapper>
135
Relay .204چیه؟
Relayیه فریم ورک جاواسکریپتـه که برای ارائه یک الیه داده و ارتباط client-serverبه
برنامههای وب با استفاده از الیه viewریاکت استفاده میشه.
npx create-react-app my-app --typescript
# or
yarn create react-app my-app --typescript
ولی برای ورژنهای پایینتر وقتی داریم یه پروژه جدید می سازیم ،react scriptsگزینه
scripts-version-- رو به عنوان react-scripts-ts تنظیم میکنیم.
react-scripts-ts مجموعه ای از تنظیمات برای گرفتن پروژه create-react-app
و آوردن typeScriptداخلش هست.
حاال ساختار پروژه باید این شکلی باشه:
my-app/
├─.gitignore
├─ images.d.ts
├─ node_modules/
├─ public/
├─ src/
│
└─...
├─ package.json
├─ tsconfig.json
├─ tsconfig.prod.json
├─ tsconfig.test.json
└─ tslint.json
136
مطالب متفرقه
Reselect بیاین محاسبات و مقادیر مختلف یه سفارش حمل و نقل رو با استفاده ساده از
:انجام بدیم
shopItemsSelector,
subtotalSelector,
taxPercentSelector,
);
137
(export const totalSelector = createSelector
subtotalSelector,
taxSelector,
)} (subtotal, tax) => ({ total: subtotal + tax
)
{ = let exampleState
{ shop:
taxPercent: 8,
[ items:
{ name: 'apple', value: 1.20 },
{ name: 'orange', value: 0.95 },
]
}
}
console.log(subtotalSelector(exampleState)) // 2.15
))console.log(taxSelector(exampleState
// 0.172
))console.log(totalSelector(exampleState
} // { total: 2.322
{
type: 'ADD_TODO',
'text: 'Add todo item
}
البته یه استانداردی هست که برای دادهای که میخواییم منتقل کنیم اسم متغیر انتخاب
نکنیم و از ویژگی payloadبراش استفاده کنیم ،مثال فوق با این استاندارد به شکل زیر
میتونه پیادهسازی بشه:
{
type: 'ADD_TODO',
'payload: 'Add todo item
}
138
.209استاتیک شی با کالسهای ES6در Reactکار می کنه؟
{(someComponent= React.createClass
{ statics:
{ )(someMethod: function
//..
}
}
)}
اما میتونیم استاتیکها رو داخل کالسهای ES6یا خارج از کالس مثل زیر بنویسیم،
{ class Component extends React.Component
{ = static propTypes
//...
}
{ )(static someMethod
//...
}
}
{ class Component extends React.Component
....
}
}Component.propTypes = {...
}Component.someMethod = function(){....
ریداکس میتونه به عنوان یه محل برای ذخیره داده برای الیه UIاستفاده بشه .رایج ترین
کاربرد ریداکس برای ریاکت و ریاکت نیتیو هستش ،ولی یه سری کارهایی هم برای
هماهنگ کردنش با Angular، Angular 2، Vue، Mithrilو موارد دیگه موجوده .ریداکس
به راحتی یه مکانیسم اشتراکی ارائه میده که میتونه برای کدهای دیگه هم استفاده بشه.
139
ریداکس در اصل توی ES6نوشته شده و برای buildروی ES5با Webpackو Babelکار
کردن ،در حقیقت ما باید بتونیم بدون توجه به مراحل و نسخه جاواسکریپت ازش استفاده
کنیم .ریداکس همینطور یه ساختار UMDارائه میده که میتونه مستقیم و بدون هیچگونه
وابستگی به شکل مستقیم روی مرورگر مورد استفاده قرار بگیره.
{(const InitializeFromStateForm = reduxForm
form: 'initializeFromState',
enableReinitialize: true
)})(UserEdit
{ = Component.PropTypes
[(size: PropTypes.oneOfType
PropTypes.string,
PropTypes.number
)]
}
میتونیم SVGرو مستقیما به عنوان یه کامپوننت به جای لود کردنش به عنوان یه فایل
ایمپورت کنیم .این ویژگی توی react-scripts@2.0.0 و ورژنهای باالتر در دسترسه.
140
import { ReactComponent as Logo } from './logo.svg'
<div>
<Logo />
</div>
در طول به روزرسانی دو بار، به عنوان یه تابع درون خطی تعریف بشهref callback اگه
این موضوع به خاطر اینه.DOM و بعد دوباره با عنصرnull یه بار با مقدار،فراخوانی میشه
قبلی رو پاکref پس ریاکت باید،که یه نمونه جدیدی از تابع با هر بار رندر ساخته میشه
.کنه و یه نمونه جدید ایجاد کنه
handleSubmit = () => {
render () {
return (
<form onSubmit={this.handleSubmit}>
<input
type='text'
<button type='submit'>Submit</button>
</form>
یه راه. یه بار صدا زده بشهref callback ، شدmountاما انتظار ما اینه که وقتی کامپوننت
. برای تعریف تابع هستشclass property syntax ES6 حل سریع استفاده از
141
{ class UserForm extends Component
{ >= )( = handleSubmit
)console.log("Input Value is: ", this.input.value
}
{ >= )setSearchInput = (input
this.input = input
}
{ )( render
( return
>}<form onSubmit={this.handleSubmit
<input
'type='text
ref={this.setSearchInput} /> // Access DOM input in
handle submit
><button type='submit'>Submit</button
></form
)
}
}
مفهوم render hijackingبه معنی توانایی کنترل اینکه چه کامپوننتی خروجی بقیه رندر
شدن یه کامپوننت دیگه باشه هست .در واقع ما میتونیم با قرار دادن کامپوننت خودمون
توی یه کامپوننت با اولویت باال( )HOCیه تغییراتی بهش بدیم ،مثال یه سری propبهش
اضافه کنیم یا تغییرات دیگهای که باعث تغییر منطق رندر بشه HOC .در واقع hijackingرو
فعال نمیکنه اما با استفاده از HOCاین امکان رو فراهم میکنیم که کامپوننت بتونه رفتار
متفاوتی رو موقع رندر داشته باشه.
142
Props Proxy
تو این روش ،متد رندر HOCیه عنصر ریاکت از نوع WrappedComponentرو برمی
گردونه که در واقع همون کامپوننت اصلی هست که از پارامتر ورودی تابع گرفتیم .با رندر
کردن اون کامپوننت توسط این تابعprop ،هایی که HOCدریافت میکنه رو به کامپوننت
انتقال میدیم و میتونیم propهای دیگهای هم بهش اضافه کنیم ،به خاطر همین بهش
Props Proxyگفته میشه.
{ )function ppHOC(WrappedComponent
{ return class PP extends React.Component
{ )(render
>return <WrappedComponent {...this.props}/
}
}
}
Inheritance Inversion
توی این روش ،کالس HOCبرگشت داده شده( )Enhancerاز WrappedComponent
دریافت شده extendمیشه و به همین دلیل میتونیم به متدهای اون کامپوننت دسترسی
داشته باشیم و با این دسترسی خیلی راحت میتونیم متد renderرو هم فراخوانی کنیم.
{ )function iiHOC(WrappedComponent
{ return class Enhancer extends WrappedComponent
{ )(render
)(return super.render
}
}
}
اعداد رو باید از طریق آکوالد همونطور که رشته رو داخل کوتیشن قرار میدیم ،انتقال بدیم.
143
.219الزمه همه stateها رو توی ریداکس مدیریت کنیم؟ لزومی به استفاده
از stateداخلی داریم؟
این به تصمیم توسعه دهنده بستگی داره ولی بهتره که از عمومی سازی دادههای
غیرضروری خودداری کنین .این وظیفه توسعه دهندهست که بررسی کنه چه نوعی از
stateها برنامه رو تشکیل بده و هر stateکجا باید قرار بگیره .به شکل کلی این شرطها رو
قبل از انتقال stateلوکال به stateعمومی بررسی کنین:
اینا قوانینی هستن که تعیین می کنن چه نوع داده ای باید توی ریداکس قرار بگیره
.1آیا بقیه قسمتای برنامه به این دادهها اهمیت میدن؟
.2آیا نیازه که بتونیم یه سری دادهها رو از روی این دادههای اصلی به دست
بیاریم؟
.3آیا از این دادهها توی چندین کامپوننت استفاده میشه؟
.4آیا نیازه که بتونیم یه stateرو به یه بازه زمانی خاصی برگردونیم؟
.5آیا میخوایم داده رو توی حافظه نگه داریم؟ (یعنی به جای درخواست مجدد ،از
اطالعات موجود توی stateاستفاده کنیم)
ریاکت به صورت پیش فرض و بدون هیچگونه پیکربندی ،یه ServiceWorkerبرامون ایجاد
میکنه ServiceWorker .یه APIوب هستش که توی ذخیره کردنassetها و فایلهای
دیگه بهمون کمک میکنه تا وقتی کاربر آفالینه یا سرعت اینترنتش پایینه ،بازم بتونه نتایج
رو روی صفحه ببینه .به این ترتیب بهمون کمک میکنه تا تجربه کاربری بهتری ایجاد کنیم .با
استفاده از متد registerServiceWorkerکه ریاکت فراهم میکنه ،سرویس خودمون رو
روی مرورگر کاربر نصب میکنیم و میتونیم از مزایایی که گفتیم بهرهمند بشیم.
import
;'React from 'react
import
;'ReactDOM from 'react-dom
import
;'App from './App
import
;'registerServiceWorker from './registerServiceWorker
;))'ReactDOM.render(<App />, document.getElementById('root
;)(registerServiceWorker
گ
144
.221چطوری با استفاده از تابع setStateاز رندر غیرضروری جلوگیری کنیم؟
میتونیم مقدار فعلی یه stateرو با مقدار موجود مقایسه کنیم و تصمیم بگیریم که state
رو تغییر بدیم یا نه .میدونیم اگه یه setStateغیر ضروری انجام بدیم ،کامپوننتمون
ریرندر میشه پس اگه مقادیر یکسان بود برای جلوگیری از رندر مجدد نباید استیت رو مجددا
ست کنیم .برای مثال ،اطالعات پروفایل کاربر توی مثال زیر به صورت شرطی رندر شده:
{ >= )const getUserAddress = (user
;const latestAddress = user.address
{ )if (address !== latestAddress
;)setAddress(address
}
;}
.222توی نسخه ۱۶ریاکت چطوری میشه آرایه Strings ،و یا عدد رو رندر
کنیم؟
آرایهها :از نسخه ۱۶به باالی ریاکت ،بر خالف نسخههای قدیمی ،نیازی نیست مطمئن
بشیم که کامپوننتمون یه المنت یا کامپوننت ریاکت برمیگردونه
.
میتونیم عناصر شبیه هم رو بدون نیاز به عنصر بسته بندی به عنوان یه آرایه برگردونیم .به
عنوان مثال ،بیاین لیست توسعه دهندگان زیر رو در نظر بگیریم:
{ >= )( = const ReactJSDevs
[ return
<li key="1">John</li>,
<li key="2">Jackie</li>,
<li key="3">Jordan</li>,
;]
;}
ه ادغام کنیم:
به همین شکل میتونیم آیتمهای این آرایه رو توی یه کامپوننت دیگ
145
{ >= )( = const JSDevs
( return
><ul
><li>Brad</li
><li>Brodge</li
><ReactJSDevs /
><li>Brandon</li
></ul
;)
;}
رشتهها و اعداد :میتونیم انواع رشتهها و اعداد رو با توی کامپوننتمون رندر کنیم:
// String
{ >= )( = const StringComponent
;'return 'Welcome to ReactJS questions
}
// Number
{ >= )( = const NumberComponent
;return 2018
}
تا اینجای مثالها بارها از هوکها استفاده کردیم ،هوکها بهمون این امکان رو میدن که
بدون نوشتن کالس از stateو ویژگیهای دیگه ری اکت استفاده کنیم
.
بیاین یه مثال از هوک useStateببینیم:
146
;"import { useState } from "react
{ )(function Example
"// Declare a new state variable, which we'll call "count
;)const [count, setCount] = useState(0
( return
><div
><p>You clicked {count} times</p
<button onClick={() => setCount(count + 1)}>Click
>me</button
></div
;)
}
npm install eslint-plugin-react-hooks@next
147
// Your ESLint configuration
{
[ "plugins":
//...
""react-hooks
],
{ "rules":
//...
""react-hooks/rules-of-hooks": "error
}
}
نکته این پالگین به صورت پیش فرض در نظر گرفته شده تا در ساخت React Appازش
استفاده کنیم.
Redux Flux
148
.1توی React Routerورژن API ،۴کال در مورد کامپوننت هاست .یه Router
میتونیم به عنوان یه کامپوننت تکی ( ) >BrowserRouter< تجسم کنیم که
کامپوننتهای روتر فرزند ( ) >Route< رو دسته بندی میکنه.
.2نیازی به تنظیم دستی historyنداریم .روتر از طریق بسته بندیrouteها با
کامپوننت از historyنگهداری میکنه.
.3اندازه برنامه فقط به یه ماژول روتر خاص ( Web, coreیا )nativeکاهش پیدا
میکنه.
بعد از اینکه یه خطا داخل یه کامپوننت با سلسله مراتب پایینتر رخ داد ،متد
componentDidCatchصدا زده میشه .این متد دو تا پارامتر دریافت میکنه:
:error .1آبجکت error
:info .2یه آبجکت با کلید componentStackکه شامل اطالعاتیه در مورد اینکه
کدوم کامپوننت خطا ایجاد کرده.
ساختار متد به صورت زیر هستش:
)componentDidCatch(error, info
149
.233چرا نیازی به error boundariesبرای event handlerها نیست؟
{ class MyComponent extends React.Component
{ )constructor(props
;)super(props
;} this.state = { error: null
}
{ >= )( = handleClick
{ try
// Do something that could throw
{ )} catch (error
;)} this.setState({ error
}
;}
{ )(render
{ )if (this.state.error
;>return <h1>Caught an error.</h1
}
;>return <div onClick={this.handleClick}>Click Me</div
}
}
بلوک try..catchبا نوشتن کد دستوری دور هر بخش از برنامه کار میکنه در حالی که error
boundaryها برای رندر کردن یه رابط کاربری پشتیبان روی صفحه در نظر گرفته شدن
.
برای مثال ،بلوک try catchبه شکل کد دستوری زیر استفاده میشه:
150
{ try
;)(showButton
{ )} catch (error
//...
}
در حالی کهerror boundaryها رابط کاربری رو به شکل پایین مدیریت می کنه:
><ErrorBoundary
><MyComponent /
></ErrorBoundary
توی ری اکت ورژن ،۱۶خطاهایی که توسط هیچ error boundaryگرفته نشن ،منجر به
unmountشدن کل درخت کامپوننت ری اکت میشن.دلیل این تصمیم اینه که رابط کاربری
خراب بهتره که کامل حذف بشه تا اینکه سر جای خودش باقی بمونه.به عنوان مثال ،برای
یه برنامه پرداخت بهتره که هیچی رندر نکنیم تا اینکه بخوایم یه مقدار اشتباه رو نشون
بدیم.
میزان و محل استفاده ازerror boundaryها بر اساس نیاز پروژه به عهده توسعه
دهندهست .میتونیم از هر کدوم از روشهای زیر استفاده کنیم:
.1میتونیم روت کامپوننتهای سطح باال رو برای نمایش یه پیغام خطای عمومی
واسه کل برنامه بسته بندی کنیم.
.2همین طور میتونیم کامپوننتهای تکی رو توی یه error boundaryقرار بدیم
تا از خراب شدن کل برنامه محافظت بشه.
151
.237مزیت چاپ شدن stack traceکامپوننتها توی متن ارور boundary
ریاکت چیه؟
به غیر از پیامهای خطا و پشته جاواسکریپت ،ری اکت ورژن ۱۶پشته کامپوننت رو با نام
فایل و شماره خط با استفاده از مفهوم error boundaryنمایش میده .برای مثال،
کامپوننت BuggyCounterپشته کامپوننت رو به صورت زیر نشون میده:
متد renderتنها متد مورد نیاز توی classکامپوننت هستش .به عنوان مثال ،همه متدها
غیر از متد renderتوی classکامپوننت اختیاری هستش.
اینجا لیستی از انواعtypeهای استفاده شده و برگشت داده شده توسط متد رندر نوشته
شده:
.1عناصر ری اکت :عناصری که به ری اکت دستور میدن تا یه گره DOMرو رندر
کنه .این عناصر شامل عناصر htmlمثل >/div< و عناصر تعریف شده
توسط کاربر هستش.
.2آرایهها و fragmentها :میتونیم بجای بازگرداندن چندین عنصر ،یه آرایه از اونا
برگردونیم و اگه چندتا عنصر برمیگردونیم میشه اونا رو داخل فرگمنت گذاشت.
Portal .3ها فرزندها رو داخل یه زیرشاخه DOMمتفاوت رندر میکنه.
.4رشتهها و اعداد :رشتهها و اعداد رو به عنوان گره متنی توی DOMرندر میکنه.
Boolean .5یا :nullچیزی رندر نمیکنه اما از این typeبرای رندر کردن محتوای
شرطی استفاده میشه.
152
.240هدف اصلی از متد constructorچیه؟
{ )constructor(props
;)super(props
!// Don't call this.setState() here
;} this.state = { counter: 0
;)this.handleClick = this.handleClick.bind(this
}
نه ،اجباری نیست .به عنوان مثال ،اگه ما stateرو مقدار دهی اولیه نکنیم و متدها رو
متصل نکنیم ،نیازی به پیاده سازی constructorبرای کالس کاموننتمون نداریم.
defaultPropها به عنوان یه ویژگی روی کالس کامپوننت تعریف شده تاpropهای پیش
فرض رو برای کالس تنظیم کنه .این مورد برایpropهای undefinedاستفاده میشه نه برای
propهای .nullبه عنوان مثال بیاین یه propپیش فرض رنگ برای کامپوننت button
بسازیم.
اگه props.colorارائه نشه مقدار پیش فرض روی red تنطیم میشه .به عنوان مثال هر
جا بخوایم به prop colorدسترسی پیدا کنیم از مقدار پیش فرض استفاده میکنه.
153
render() {
این متد زمانی فراخوانی میشه که یه خطا توی کامپوننتهای فرزندان این کامپوننت رخ
ای که رخ داده رو به عنوان ورودی دریافت میکنه و باید یه مقداری روerror این متد.بده
: ساختار کلی این متد به شکل پایینـه. برگردونهstate برای به روز کردن
static getDerivedStateFromError(error)
constructor(props) {
super(props);
}
static getDerivedStateFromError(error) {
}
render() {
if (this.state.hasError) {
return this.props.children;
}
}
154
.245کدوم متدها و به چه ترتیبی در طول ریرندر فراخوانی میشن؟
تغییر درpropها یا stateمیتونه باعث به روزرسانی بشه .متدهای زیر به ترتیب ،وقتی یه
کامپوننت مجددا رندر میشه صدا زده میشه.
static getDerivedStateFromProps .1
shouldComponentUpdate .2
render .3
getSnapshotBeforeUpdate .4
componentDidUpdate .5
وقتی یه خطایی موقع رندر کردن وجود داشته باشه ،توی متد ،lifecycleیا توی
constructorهر کامپوننت فرزند ،متدهای زیر فراخوانی میشه.
static getDerivedStateFromError .1
componentDidCatch .2
بیشتر برای نمایش اینکه کدوم کامپوننت رندر شده و یا (debugاشکال زدایی) راحتتر توی
devToolsاستفاده میشه ،به عنوان مثال ،برای سهولت توی debugیه displayName
انتخاب میکنیم که نشون میده این کامپوننت ،نتیجه یه withSubscription HOC
هستش.
155
{ )function withSubscription(WrappedComponent
{ class WithSubscription extends React.Component
/*... */
}
= WithSubscription.displayName
(`WithSubscription(${getDisplayName
WrappedComponent
;`)})
;return WithSubscription
}
{ )function getDisplayName(WrappedComponent
( return
|| WrappedComponent.displayName || WrappedComponent.name
""Component
;)
}
ری اکت همه مرورگرهای معروف از جمله اینترنت اکسپلورر ۹به باال رو پشتیبانی می کنه،
اگرچه برای مرورگرهای قدیمی تر مثل IE 9و IE 10یه سریpolyfillها نیازه .اگه از polyfill
es5-shimو es5-shamاستفاده کنیم در اون صورت حتی مرورگرهای قدیمی رو هم
پشتیبانی میکنه که متدهای ES5رو پشتیبانی نمیکنن.
;)ReactDOM.unmountComponentAtNode(container
156
چیه؟code-splitting .250
export { moduleA };
App.js
handleClick = () => {
import("./moduleA")
// Use moduleA
})
.catch((err) => {
// Handle failure
});
};
render() {
return (
<div>
<button onClick={this.handleClick}>Load</button>
</div>
);
}
}
157
.251مزایای حالت strictچیه؟
{ )function Glossary(props
( return
><dl
( >= ){props.items.map((item
// Without the `key`, React will fire a key warning
>}<React.Fragment key={item.id
><dt>{item.term}</dt
><dd>{item.description}</dd
></React.Fragment
}))
></dl
;)
}
یادداشت keyتنها اتریبیوتی هستش که میشه به Fragmentپاس داد .در آینده ،ممکنه از
اتریبیوتهای اضافه ای هم مثلevent handlerها پشتیبانی بشه.
از ریاکت ،16هر دو ویژگی استاندارد یا سفارشی DOMکامال پشتیبانی میشن.از اونجایی
که کامپوننتهای ریاکت اغلب هر دو نوع پراپهای DOM-relatedو customرو استفاده
میکنن ،ریاکت دقیقا مانندAPIهای DOMاز قرارداد camelCaseاستفاده میکنه .بیاین با
استفاده از ویژگیهای استاندارد HTMLچند مورد رو انتخاب کنیم.
158
<div tabIndex="-1" /> // Just like node.tabIndex DOM API
اینجا چند. چند تا نکته مهم هم داره،کامپوننتهای با اولویت باال جدا از مزایایی که داره
:مورد به ترتیب گفته شده
توی یه کامپوننتHOC استفاده از: استفاده نکنیمrender ها توی متدHOC از.1
.با متد رندر اون کامپوننت توصیه نمیشه
render() {
اون کامپوننت و همهstate کردن کامپوننتی که باعث از بین رفتنremount کد باال با
ها رو بیرون از تعریف کامپوننتHOC، در عوض. روی عملکرد تاثیر میذاره،فرزندانش شده
.اعمال میکنیم تا کامپوننت بدست اومده فقط یه بار ساخته بشه
رو روی یه کامپوننت اعمال میHOC باید کپی بشن وقتیstatic متدهای.2
کامپوننت جدید هیچ کدوم از متدهای استاتیک کامپوننت اصلی رو،کنیم
نداره
WrappedComponent.staticMethod = function () {
/*...*/
};
159
کردنش رو این مشکل غلبهreturn قبل ازcontainer میتونیم با کپی کردن متدها توی
.کنیم
function enhance(WrappedComponent) {
/*...*/
}
// Must know exactly which method(s) to copy:(
Enhance.staticMethod = WrappedComponent.staticMethod;
return Enhance;
});
”)ForwardRef(myFunction” اما اگه برای تابع رندر اسم گذاشته باشیم اونوقت به صورت
نمایش داده میشه
});
160
function logProps(Component) {
//...
// e.g. "ForwardRef(logProps(MyComponent))"
forwardRef.displayName = `logProps(${name})`;
return React.forwardRef(forwardRef);
نعیینprop رو به یه کامپوننت پاس بدیم ولی هیچ مقداری رو برای اونprop اگه یه
: به طور مثال. در نظر گرفته میشهtrue به طور پیشفرض،نکنیم
یه فریمورک محبوب و سبک برای برنامههای استاتیک و تحت سرور هستش کهNext.js
اینجا. همچنین استایل دهی و مسیریابی رو هم ارائه میده.توسط ریاکت ساخته شده
. آورده شدهNext.js ویژگیهای اصلی ارائه شده توسط
به طور پیش فرض پشتیبانی میشهserver rendering .1
تقسیم خودکار کد برای بارگذاری سریعتر صفحه.2
)) ساده سمت کالینت(مبتنی بر صفحهrouting( مسیریابی.3
)HMR( محیط توسعه زنده و سریع.4
قابل پیاده سازیهnodejs دیگهای رویHTTP یا هر سرورExpress با.5
161
.6با تنظیمات Babelو Webpackقابل تنظیمه
>}<button onClick={this.handleClick
بله ،میتونیم استفاده کنیم .این معموال سادهترین راه برای انتقال پارامترها به توابع
برگشتی هستش .اما موقع استفاده ازشون اگه خیلی پرفورمنس برامون مهمه یادداشت
پایین رو باید مدنظر داشته باشیم.
{ class Foo extends Component
{ )(handleClick
;)"console.log("Click happened
}
{ )(render
return <button onClick={() => this.handleClick()}>Click
;>Me</button
}
}
یادداشت :استفاده از تابع arrowتوی متد رندر ،با هر بار اجرا ،یه تابع جدید ایجاد میکنه که
هر بار که کامپوننت رندر میشه ،مجدد ایجاد شده و توی حافظه مصرفی و ...تاثیر میزاره.
162
:Throttling .1تغییر براساس زمان و به شکل پیوسته .برای مثال میشه با
استفاده از تابع throttle._ روی کتابخونه (lodashروی npmموجوده)
انجامش داد.
:Debouncing .2تغییر براساس یک مدت زمان بدون فعالیت .میشه با استفاده
از تابع debounce._ روی کتابخونه lodashانجامش داد.
Throttling .3با : RequestAnimationFrameتغییر بر اساس
.requestAnimationFrameمیشه از کتابخونه یا تابع raf-schdروی lodash
استفاده کرد.
;const name = response.potentiallyMaliciousInput
;>const element = <h1>{name}</h1
مقدار چاپ شده در مقابل حمله XSSیا همون ( )Cross-site-scriptingدر امان خواهد
بود.
میشه (UIتولید شده توسط رندرشدن elementها) رو با پاس دادن مقدار جدید به متد رندر
از ReactDOMبه روزرسانی کرد .برای مثال بیایین یه ساعت رو بررسی کنیم که با هر
تیکتاک باید رندر بشه و ما این کار رو با ReactDomمیخواییم انجام بدیم:
163
{ )(function tick
( = const element
><div
><h1>Hello, world!</h1
><h2>It is {new Date().toLocaleTimeString()}.</h2
></div
;)
;))"ReactDOM.render(element, document.getElementById("root
}
;)setInterval(tick, 1000
وقتی یه کامپوننت میسازید ،فرقی هم نمیکنه تابع یا کالس ،نباید روی propهای ورودیش
تغییری انجام بده .به این کامپوننت نگاه کنید:
{ )function Capital(amount, interest
;return amount + interest
}
این کامپوننت pureنامیده میشه چون با ورودیهای یکسان ،همواره خروجی یکسانی تولید
میکنه و تغییری روی اونا نمیده .به همین خاطر ریاکت یه قانون ساده داره که میگه" :همه
کامپوننتها باید مثل یه pureکامپوننت رفتار کنن و در مورد propهای ورودی هیچ تغییری
روشون ندن".
164
{ )constructor(props
;)super(props
{ = this.state
posts: [],
][ comments:
;}
}
حاال میتونیم به شکل جداگانه هر کدوم از این دادهها رو با )(setStateجداگانه مثل زیر
آپدیت کنیم:
{ )(componentDidMount
{ >= fetchPosts().then(response
{(this.setState
posts: response.posts
;)}
;)}
{ >= fetchComments().then(response
{(this.setState
comments: response.comments
;)}
;)}
}
همونطوری که باالتر هم گفته شد )} this.setState({ comments ،فقط بخش مربوط به
نظرات رو به روز میکنه و کاری با بقیه بخشها نداره.
موقع iterationsیا داخل حلقهها ،مرسوم هست که یه پارامتر اضافی دیگه به
eventHandlerپاس بدیم ،مثال آی کاربر و . ...این میتونه arrow-functionها یا متد
bindانجام بشه .بیایین یه نگاهی به تابع آپدیت کاربر داخل یه جدول بندازیم:
در هر دو حالت پارامتر eبه عنوان دومین پارامتر پاس داده میشود .در مورد تابع arrow
باید به شکل مستقیم اون رو پاس بدیم و در مورد مثال bindبه شکل اتوماتیک پاس داده
165
.میشه
function Greeting(props) {
if (!props.loggedIn) {
return null;
constructor(props) {
super(props);
render() {
return (
<div>
<UserDetails name={this.state.name}>
</div>
);
}
}
166
.1لیست و آیتمهاش ثابت هستن و کامپایل نمیشن و تغییر نمیکنن.
.2آیتمهای موجود توی لیست ،فیلدی برای idندارن.
.3لیست موردنظر هیچ وقت مجددا تولید و مقداردهی نمیشه ،یا فیلتر نمیشه.
Keyهایی که در طول رندر کردن یک آرایه استفاده میشن ،الزاما باید در همسایگی خودشون
منحصر به فرد باشن ولی هیچ لزومی نداره که به شکل عمومی منحصر به فرد باشن .برای
مثال میتونین یه کلید یکسان رو موقع رندر کردن دو تا آرایه متفاوت استفاده کنین ،مثل:
{ )function Book(props
( = const index
><ul
( >= ){props.pages.map((page
><li key={page.id}>{page.title}</li
}))
></ul
;)
( >= )const content = props.pages.map((page
>}<div key={page.id
><h3>{page.title}</h3
><p>{page.content}</p
><p>{page.pageNumber}</p
></div
;))
( return
><div
}{index
><hr /
}{content
></div
;)
}
Formikیه کتابخونه مدیریت فرم برای ریاکتـه که به شکل پیشفرض امکان زیادی مثل
اعتبارسنجی ،نگهداری سابقه تغییر فیلدها و مدیریت ثبت شدن فرم رو فراهم میکنه .در
حالت کلی میشه به صورت زیر دستهبندیشون کرد:
167
.1دریافت و فراهم کردن دادههای فیلدهای فرم
.2اعتبارسنجی و مدیریت پیامهای خطا
.3مدیریت ثبت شدن فرم
از فرمیک میشه برای فرمهای مقیاسپذیر ،بهینه ،بی دردسر و حتی پیچیده استفاده کرد.
APIفرمیک هم بسیار ساده و قابل فهمه.
.271چرا اجباری برای استفاده از ارثبری توی ریاکت نیست؟ مزیتی داره؟
بله ،میشه از وب کامپوننتها توی برنامه ریاکتی استفاده کرد .اگرچه خیلی از
توسعهدهندهها از این قابلیت استفاده نمیکنن ،ممکنه بیشتر زمانهایی به کارمون بیاد که
168
برای مثال وب کامپوننت.از کتابخونههای خارجی توی برنامهمون میخواییم استفاده کنیم
: رو میشه به شکل زیر استفاده کردVaadin انتخاب تاریخ
import "./App.css";
import "@vaadin/vaadin-date-picker";
render() {
return (
<div className="App">
</div>
);
}
}
ارائه شده بود کهECMAScript داینامیک در ابتدا به شکل یه پروپوزال رویimport ساختار
رو توی برنامهمونcode-splitting میتونیم با استفاده از این قابلیت به راحتی.تایید شد
: به مثال پایین توجه کنین.داشته باشیم
عادیImport .1
console.log(add(10, 20));
داینامیکImport .2
import("./math").then((math) => {
console.log(math.add(10, 20));
});
169
این اجازه رو میده که importداینامیک رو مثل یه کامپوننت عادی باهاش برخورد کنین.
بزارین یه مثال بزنیم:
;"import loadable from "@loadable/component
>= )((const OtherComponent = loadable
;))"import("./OtherComponent
{ )(function MyComponent
( return
><div
><OtherComponent /
></div
;)
}
.275کامپوننت suspenseچیه؟
اگه یه ماژول شامل importداینامیک باشه و هنوز رندر نشده نباشه ،توی کامپوننت
والدش باید یه رابط کاربری loadingبراش نمایش داده بشه .این بخش میتونه با
کامپوننت Suspenseمدیریت بشه .برای مثال کامپوننتهای پایین رو ببینید که از
Suspenseدر طول مدت بارگذاری کامپوننت دوم استفاده میکنن:
170
.276چطوری به ازای routeمیتونیم code splittingداشته باشیم؟
یکی از بهترین جاها برای انجام ،code-splittingانجام اون به ازای routeهای برنامهست.
وقتی میخواییم یه routeجدید رو بارگذاری کنیم کاربر انتظار داره که صفحه عوض بشه،
پس با نمایش fallbackو استفاده از suspenseتجربه کاربری خیلی بهتر میشه .بیایین یه
مثال از روترها در کنار استفاده از lazyو suspenseببینیم:
در مثال فوق به ازای هر routeیک فایل bundleمجزا ساخته میشه و برنامه وقتی میخواد
بارگذاری بشه ،فقط فایل مربوط به اون routeلود میشه که باعث افزایش سرعت لود و
بهبود تجربه کاربری میشه.
171
//Lets create a context with a default theme value "luna"
render() {
return (
<ThemeContext.Provider value="nova">
<Toolbar />
</ThemeContext.Provider>
);
}
}
return (
<div>
<ThemedButton />
</div>
);
172
استفاده میکنین؟contextType چطوری از.279
componentDidMount() {
}
componentDidUpdate() {
/*... */
}
componentWillUnmount() {
/*... */
}
render() {
}
}
MyClass.contextType = MyContext;
فیلد استاتیک.2
. استفاده کنیمcontextType برایclass میتونیم از یه فیلد استاتیک روی
render() {
}
}
173
consumer .280چیه؟
><MyContext.Consumer
}{value => /* render something based on the context value */
></MyContext.Consumer
نکته :با استفاده از هوک useContextدیگه الزم نیست به این شکل از کامپوننت
Consumerاستفاده کنیم و به راحتی میشه به مقدار contextدست پیدا کرد.
contextاز رفرنس برای متوجه شدن اینکه چه زمانی به رندر شدن مجدد نیاز داریم،
استفاده میکنه ,.حالتهایی هست که میتونه باعث رندر شدن ناخواسته کامپوننت
consumerزمانی که والد providerریرندر شد بشه .برای مثال ،کدپایین همهیl
consumerها رو با هر ریرندر توی کامپوننت Providerریرندر میکنه .چون objectبه
عنوان ورودی providerداده شده که با هر بار رندر رفرنس اون objectتغییر میکنه.
{ class App extends React.Component
{ )(render
( return
>}} "<Provider value={{ something: "something
><Toolbar /
></Provider
;)
}
}
174
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
render() {
return (
<Provider value={this.state.value}>
<Toolbar />
</Provider>
);
}
}
اون توسط ریاکت. نیستprop یهref داخل کامپوننتها پاس داده نمیشه چونref
بهref ، اضافه کنیمHOC رو تویref اگه ما. به طور متفاوتی هندل میشهkey درست مثل
تو این. شدهwrapped نه به کامپوننت، اشاره میکنهcontainer بیرونی ترین کامپوننت
برای مثال با استفاده از. استفاده کنیمForward Ref API مورد ما میتونیم از
. داخلی بفرستیمFancyButton رو به کامپوننتref میتونیمReact.forwardRef API
175
function logProps(Component) {
componentDidUpdate(prevProps) {
render() {
});
:های ورودی به کامپوننتـمون استفاده کنیمprop برای الگ کردنHOC بیایید از این
focus() {
//...
//...
توی این مورد. بفرستیمFancyButton بسازیم و اونو به کامپوننتref حاال بیاین یه
. رو روی عنصر دکمه تنظیم کنیمfocus میتونیم
ref.current.focus();
176
توابع منظم یا کالس کامپوننتها آرگومان refرو دریافت نمی کنن و refتویpropها هم در
دسترس نیست .آرگومان دوم refفقط زمانی وجود داره که ما کامپوننت رو با
React.forwardRefتعریف کنیم.
اگه از ES6استفاده نمی کنیم ممکنه الزم باشه که به جای اون از ماژول create-react-
classاستفاده کنیم .برایpropهای پیش فرض ،نیاز داریم که )(getDefaultPropsرو به
عنوان یه تابع روی آبجکت پاس داده شده تعریف کنیم .در حالی که برای stateاولیه ،باید
یه متد getInitialStateجداگانه ارائه بدیم که یه stateاولیه برمیگردونه.
{(var Greeting = createReactClass
{ )( getDefaultProps: function
{ return
name: "Jhohn",
;}
},
{ )( getInitialState: function
;} return { message: this.props.message
},
{ )( handleClick: function
;)console.log(this.state.message
},
{ )( render: function
;>return <h1>Hello, {this.props.name}</h1
},
;)}
177
استفاده میکنیم اتصال خودکار برای همه روشها درcreateReactClass اگه از:یادداشت
هاevent handler برایconstructor ) تویbind(this. یعنی نیازی به استفاده از.دسترسه
.نیست
در واقع مناسب زمانی هست که ما. برای استفاده از ریاکت اجباری نیستJSX ،بله
syntactic فقطJSX هر عنصر. تنظیم کنیمbuild نمیخوایم کامپایلی رو توی محیط
React.createElement(component, هستش برای فراخوانیsugar
. بزنیمJSX باgreeting برای مثال بیاین یه مثال.)props,...children
}
}
ReactDOM.render(
document.getElementById("root")
);
}
}
ReactDOM.render(
document.getElementById("root")
);
گ
178
.287الگوریتمهای diffingریاکت چی هستن؟
ریاکت نیاز به استفاده از الگوریتمها داره تا بفهمه چطور به طور موثر UIرو برای مطابقت با
آخرین درخت بهروز کنه .الگوریتمهای مختلفی در حال تولید حداقل تعداد عملیات برای
تبدیل یه درخت به درخت دیگه هستن .با این حال ،الگوریتمها به ترتیب )O(n3دارای
پیچیدگی هستن ،جایی که nتعداد عناصر موجود در درخت هستش
.
توی این مورد ،برای نمایش ۱۰۰۰عنصر به ترتیب یک میلیارد مقایسه نیازه و این خیلی
هزینه بر هستش .در عوض ریاکت یه الگوریتم ابتکاری )O(nرو بر اساس دو پیش فرض
پیادهسازی میکنه:
.1دو عنصر از انواع مختلف باعث تولید درختهای مختلفی میشه.
.2برنامه نویس میتونه اشاره کنه که کدوم یکی از عناصر فرزند ممکنه توی
رندرهای مختلف با یه propاصلی پایدار باشن.
><div className="show" title="ReactJS" /
><div className="hide" title="ReactJS" /
179
بهروز میکنه و متدهای componentWillReceivePropsو
componentWillUpdateرو روی نمونه اصلی صدا میزنه .بعد از اون متد render
صدا زده میشه و الگوریتم ،diffنتیجه قبلی و نتیجه جدید رو جستجو میکنه.
Recursing .4روی فرزند
:
وقتی recursingروی فرزند از یه DOMاستفاده میشه ،ریاکت میاد روی لیست
فرزندان حلقه میزنه و اگه تغییری رو مشاهده کرد میاد تغییر رو اعمال
میکنه( mutationانجام میده) .برای مثال ،وقتی یه المنت به انتهای یه لیست
اضافه میشه ،تغییر بین این دوحالت به راحتی انجام میشه:
><ul
><li>first</li
><li>second</li
></ul
><ul
><li>first</li
><li>second</li
><li>third</li
></ul
><ul
><li key="2015">Duke</li
><li key="2016">Villanova</li
></ul
><ul
><li key="2014">Connecticut</li
><li key="2015">Duke</li
><li key="2016">Villanova</li
></ul
180
.1مدیریت focus، text selectionیا پخش media
.2راهاندازی انیمیشنهای ضروری.
.3ادغام با کتابخانههای .third-party DOM
<Mouse
( >= )children={(mouse
><p
}The mouse position is {mouse.x}, {mouse.y
></p
})
>/
در واقع نیازی نیست که از propفرزند توی لیست ""attributeها توی عنصر JSXنام برده
بشه .در عوض میتونیم اونو مستقیما توی المنت نگه داریم.
><Mouse
( >= ){(mouse
><p
}The mouse position is {mouse.x}, {mouse.y
></p
})
></Mouse
وقتی که از روش باال (تابع بدون نام) برای رندر کردن فرزند استفاده میکنیم ،به صراحت و
اجبار میگیم که فرزند پاس داده شده ،باید یه تابع توی propTypeهامون باشن.
{ = Mouse.propTypes
children: PropTypes.func.isRequired,
;}
181
.291مشکل استفاده از render propsبا pure componentها چیه؟
اگه بیایم داخل متد رندر یه تابعی ایجاد کنیم ،در این صورت هدف اصلی pure
componentها رو نفی کردیم .چون که مقایسه سطحیpropها معموال همیشه مقدار
falseرو برایpropهای جدید برمی گردونه و هر رندر در این حالت یه مقدار جدیدی رو برای
رندر ارائه میده .با تعریف یه تابع رندر به عنوان متد instanceمیتونیم این مشکل رو حل
کنیم.
{ )function withMouse(Component
{ return class extends React.Component
{ )(render
( return
<Mouse
=render={(mouse) => <Component {...this.props} mouse
}>{mouse} /
>/
;)
}
;}
}
این روش رندر کردن propها ،انعطاف پذیری استفاده از هر دو الگو رو میده.
.293تکنیک windowingچیه؟
182
کتابخونههای معروف windowingهستن که چندین کامپوننت قابل استفاده مجدد رو
برای نمایش لیست ها ،شبکهها و دادههای جدولی فراهم میکنن.
مقادیر جعلی مثل false، null، undefinedو trueمعتبر هستند ولی هیچ چیزی رو رندر
نمیکنن .اگه بخوایم اونا رو نمایش بدیم باید به رشته تبدیلشون کنیم .بیاین یه مثال در
مورد تبدیل به رشته بزنیم،
><div>My JavaScript variable is {String(myVariable)}.</div
portalهای ریاکت وقتی که یه کامپوننت والد سرریز( )overflowمیشه خیلی کاربرد دارن،
برای مثال :المنتهای hiddenیا استایلهایی که روی contextتاثیر دارن(z-index،
position، opacityو )...و الزمه که به شکل ظاهری containerاون المنت رو بشکنید و
استایل دهی رو عمومیتر کنید .برای مثالdialog :ها ،پیامهای notificationعمومی،
tooltipها و ...از این قبیل موارد هستند.
183
{ )(render
( return
>}<form onSubmit={this.handleSubmit
><label
User Name:
<input
"defaultValue="John
"type="text
>ref={this.input} /
></label
><input type="submit" value="Submit" /
></form
;)
}
همین کار برای select و textArea هم انجام میشه ولی برای checkbox باید از
defaultcheckedاستفاده کنیم.
حتی اگه tech stackاز توسعه دهنده ای به توسعه دهنده دیگه متفاوت باشه ،معروف
ترین stackتوی کد پروژه biolerplateری اکت استفاده شده boilerplate .به طور عمده از
ریداکس و ریداکس ساکا برای مدیریت استیت و ساید افکتهای ناهمزمانstyled- ،
componentsبرای استایل دهی کامپوننت ها axios ،برای فراخوانی rest apiو
پشتیبانیهای دیگه از قبیل webpack، reselect، ESNextو
.babel
میتونیم پروژه https://github.com/react-boilerplate/react-boilerplateرو کلون
کنیم و کار روی هر پروژه ری اکت جدیدی رو شروع کنیم.
184
.5در صورت به روز رسانی یه المنت ،یه DOMجدید ایجاد میکنه.
مجازی :DOM
.1به روز رسانیها سریع هستن
.2دستکاری DOMخیلی راحته.
HTML .3رو نمیتونیم مستقیما به روز رسانی کنیم.
.4هیچ اتالف حافظه ای وجود نداره.
.5در صورت به روز رسانی یه المنت JSX ،رو به روز میکنه.
npm install bootstrap
.3بسته
:React Bootstrap
در این حالت میتونیم bootstrapرو به برنامه ری اکت اضافه کنیم تا با استفاده از
بستههایی که کامپوننتهای ری اکت رو دوباره ساخته تا منحصرا به عنوان
کامپوننتهای ری اکت کار کنند .معروف ترین بستهها برای این کار اینا هستند
react-bootstrap .1
reactstrap .2
185
Facebook .1
Uber .2
Instagram .3
WhatsApp .4
Khan Academy .5
Airbnb .6
Dropbox .7
Flipboard .8
Netflix .9
PayPal .10
ریاکت هیچ ایدهای راجع به اینکه استایلها چطوری تعریف شدن نداره اما اگه تازه کار
باشین میتونین از یه فایل جداگانه * css.که مث قبال توی پروژههای ساده استفاده میشد
کمک بگیرین و با استفاده از classNameاز استایلها استفاده کنین CSS In Js .یه بخش
از خود ریاکت نیست و توسط کتابخونههای third-partyبهش اضافه شده اما اگه
میخوایین .ازش( )CSS-In-JSاستفاده کنین کتابخونه styled-componentsمیتونه
گزینه خوبی باشه.
نه .ولی میتونین از هوکها توی بعضی از کامپوننتهای قدیمی یا جدید استفاده کنین و
سعی کنین باهاش راحت باشین البته برنامهای برای حذف classesاز ریاکت هنوز وجود
نداره.
هوک این افکت اسمش useEffect هستش و میشه خیلی ساده ازش برای فراخوانی
APIبا استفاده از axiosاستفاده کرد .نتیجه درخواست رو هم خیلی ساده میشه ریخت تو
یه stateداخلی از componentکه وظیفه این ثبت شدن داده رو هم تابع setterاز
186
useStateبه عهده میگیره
.
خب بزارین یه مثال بزنیم که لیست مقاالت رو از یه APIمیگیره:
;"import React, { useState, useEffect } from "react
;"import axios from "axios
{ )(function App
;)} ][ const [data, setData] = useState({ hits:
{ >= )( useEffect(async
(const result = await axios
""http://hn.algolia.com/api/v1/search?query=react
;)
;)setData(result.data
;)][ },
( return
><ul
( >= ){data.hits.map((item
>}<li key={item.objectID
><a href={item.url}>{item.title}</a
></li
}))
></ul
;)
}
;export default App
دقت کنین که یه آرایه خالی به عنوان پارامتر دوم به هوک effectدادیم که فقط موقع
mountشدن درخواست رو بفرسته و الزم نباشه با هر بار رندر درخواست زده بشه ،اگ الزم
بود با تغییرات یه مقدار(مثال شناسه مقاله) درخواست APIرو مجددا بزنیم ،میتونستیم
عنوان متغیر رو توی اون آرایه قرار بدیمش و با هر تغییر اون متغیر افکت مجددا اجرا بشه.
هوکها میشه گفت همه موارد کارکردی کالسها رو پوشش نمیدن ولی با اضافه شدن
هوکهای جدید برنامههای خوبی برای آینده هوکها پیشبینی میشه .در حال حاضر هیچ
هوکی وجود نداره که کارکرد متدهای getSnapshotBeforeUpdateو
componentDidCatchرو محقق کنه.
187
.305نسخه پایدار ریاکت که از هوک پشتیبانی میکنه کدومه؟
ریاکت حالت پایداری از هوکها رو توی نسخه 16.8برای پکیجهای زیر منتشر کرد:
React DOM .1
React DOM Server .2
React Test Renderer .3
React Shallow Renderer .4
وقتی که با استفاده از هوک useState یه stateرو معرفی میکنیم ،یه آرایه دوتایی
برمیگردونه که اندیس اولش متغیر مورد نظر برای دسترسی به stateهست و اندیس درم
متد setterیا تغییر دهنده اون .stateیه روش اینه که با استفاده از اندیسهای آرایه و []0
و [ ]1بهشون دسترسی پیدا کنیم ولی یه کم ممکنه گیچ کننده باشه .ولی با استفاده از
حالت destructuringخیلی سادهتر میشه این کار رو انجام داد
.
برای مثال دسترسی به stateبا اندیسهای آرایه این شکلی میشد:
;)"const [user, setUser] = useState("userProfile
ایده معرفی هوک از منابع مختلفی به وجود اومد .این پایین یه لیستی ازشون رو میاریم:
.1تجربه قبلی که با functional APIتوی پکیج react-futureداشتن
.2تجربه انجمن ریاکت با پراپ renderمثل کامپوننتهای Reaction
.3متغیرهای stateو سلولهای stateتوی .DisplayScript
Subscription .4های موجود توی .Rxjs
.5کامپوننتهای reducerتوی .ReasonReact
188
.308چطوری به APIهای ضروری اجزای وب دسترسی پیدا کنیم؟
formik .309چیه؟
189
ریاکت از روش جربان داده یک طرفه استفاده میکنه .استفاده از propباعث میشه از تکرار
موارد بدیهی جلوگیری بشه و درک کردنش سادهتر از روش سنتی data-bindingدو طرفه
باشه.
190
:Noteالبته یادتون باشه که این متد توی مرورگر قابل اجرا نیست و فقط روی سرور کار
میکنه.
MobX .316چیه؟
MobXیه راهحل ساده scalable ،برای مدیریت stateهست که خیلی قوی تست شده.
این روش برای برنامهنویسی تابعی کنشگرا( )TFRPاستفاده میشه .برای برنامههای
ریاکتی الزمه که پکیجهای زیر رو نصب کنین:
npm install mobx --save
npm install mobx-react --save
191
MobX Redux موضوع
نه ،اجبار برای یادگرفتن es2015/es6برای کار با ریاکت وجود نداره .ولی توصیه شدیدی
میشه که یاد بگیریدش چون منابع خیلی زیادی هستن که به شکل پیشفرض با es6کار
شدن .بزارین یه نگاه کلی به مواردی که الزاما با es6کارشدن رو ذکر کنیم:
:Destructuring .1برای گرفتن مقادیر propو استفاده از اونا توی کامپوننت
// in es 5
;var someData = this.props.someData
;var dispatch = this.props.dispatch
// in es6
;const { someData, dispatch } = this.props
// in es 5
=<SomeComponent someData={this.props.someData} dispatch
>{this.props.dispatch} /
// in es6
><SomeComponent {...this.props} /
// es 5
{ )var users = usersList.map(function (user
;>return <li>{user.name}</li
;)}
// es 6
;)>const users = usersList.map((user) => <li>{user.name}</li
192
Concurrent Rendering .319چیه؟
Concurrent renderingباعث میشه برنامه ریاکتی بتونه توی رندر کردن درخت
کامپوننتها به شکل مسئوالنهتری عمل کنه و انجام این رندر رو بدون بالک کردن thread
اصلی مرورگر انجام بده .این امر به ریاکت این اجازه رو میده که بتونه اجرا شدن یه رندر
طوالنی رو به بخشهای مرتب شده بر اساس اولویت تقسیم کنه و توی پیکهای مختلف
رندر رو انجام بده .برای مثال وقتی حالت concurrentفعال باشه ،ریاکت یه نیم نگاهی
هم به بقیه تسکهایی که هنوز انجام نشدن داره و اگه تسک با اولویت دیگهای رو ببینه،
حالت فعلی که داشت رندر میکرد رو متوقف میکنه و به انجام کار با اولویتتر میرسه .این
حالت رو به دو روش میشه فعال کرد:
.۱برای یه بخش از برنامه با wrapکردن کامپوننت توی تگ :concurrent
><React.unstable_ConcurrentMode
><Something /
></React.unstable_ConcurrentMode
;)>ReactDOM.unstable_createRoot(domNode).render(<App /
هر دوتاشون به یه چیز اشاره میکنن .قبال حالت concurrentبا عنوان ""Async Mode
توسط تیم ریاکت معرفی میشد .عنوان این قابلیت به این دلیل تغییر پیدا کرد که قابلیت
ریاکت برای کار روی مرحلههای با اولویت متفاوت رو نشون بده .همین موضوع جلوی
اشتباهات در مورد طرز تفکر راجع به رندر کردن asyncرو میگیره.
193
{ = const companyProfile
website: "javascript: alert('Your website is hacked')",
;}
// It will log a warning
;><a href={companyProfile.website}>More details</a
البته بخاطر داشته باشین که نسخههای بعدی ریاکت قراره بجای warningیه ارور برای این
مورد throwکنن.
پالگین ESLintمیاد یهسری قوانین برای صحیح نوشتن هوکها توی برنامه رو الزامی
میکنه .روش تشخیص دادن هوکها هم اینطوریه که میگه اگه اسم تابعی با ” ”useشروع
بشه و درست بعد اون یه حرف بزرگ بیاد پس اون تابع هوک هستش .این پالگین در حالت
پایه این دوتا شرط رو الزام میکنه:
.1فراخوانی هوکها یا باید داخل یه تابع که عنوانش PascalCaseهست
(منظور یه کامپوننته) یا یه تابع دیگه که مثال useSomethingهست
( customهوک) انجام بشه.
.2هوکها باید توی همه رندرها با یه ترتیب مشخص اجرا بشن و هیچ شرطی
چیزی نباشه که یه بار اجازه اجرای هوک رو بده و دفعه دیگه اجازه نده.
یه کامپوننت ساده UIرو تصور کنین ،مثال یه دکمه "الیک" .وقتی که روش کلیک میکنین
رنگ از خاکستری به آبی تغییر پیدا میکنه و اگه دوباره کلیک کنید باز خاکستری میشه
.
رویش imperativeبرای انجام این کار اینطوریه:
{ ))(if (user.likes
{ ))(if (hasBlue
;)(removeBlue
;)(addGrey
{ } else
;)(removeGrey
;)(addBlue
}
}
194
الزمه اول بررسی کنیم که چه چیزی رو توی اسکرین داریم نمایش میدیم و بعدش بیایم
stateرو عوض کنیم به حالتی که میخواییم برامون نمایش انجام بشه ،توی برنامههای
بزرگ و واقعی مدیریت این حالتها خیلی میتونه سخت باشه.
در حالت مقابل ،روش declarativeمیتونه اینطوری باشه:
{ )if (liked
;>return <blueLike /
{ } else
;>return <greyLike /
}
چون روش declarativeحالتها رو جدا در نظر میگیره ،این بخش از کد براساس state
فقط تصمیم میگیره که چه ظاهری رو نمایش بده و به همین دلیل درک کردنش سادهتره.
195