ترفندهای طلایی ری اکت با مثال های کاربردی – بخش دوم

به ادامه ترفندها و نکات طلایی ری اکت خوش آمدید. در بخش اول، 20 مورد از نکات طلایی ری اکت را به همراه مثال های کاربردی بررسی کردیم. در این بخش می خواهیم 20 ترفند دیگر از ReactJS را با هم بررسی کنیم. از قبیل:
- نحوه کار با متد setState
- نحوه استفاده از متد setInterval
- کاربرد callback در state
- نحوه پیاده سازی رندر شرطی
- اعمال focus روی input
- تفاوت بین state و props
- و…
21- نحوه تغییر شماره port در اپلیکیشن ریکت:
در این بخش، می خواهیم نحوه تغییر پورت پیش فرض پروژه ریکت را آموزش دهیم. اگر اپلیکیشن react را توسط دستور create-react-app ایجاد کرده باشیم، بطور پیش فرض روی پورت 3000 لوکال هاست بالا می آید. برای تغییر این پورت پیش فرض، نیاز است یک پکیج بنام cross-env را نصب کنیم:
npm install -D cross-env # or yarn add -D cross-env
سپس فایل package.json را باز کرده و در بخش scripts کد زیر را تعریف کنید:
"start": "cross-env PORT=4006 react-scripts start"
به همین راحتی توانستیم پورت پیش فرض ریکت را به 4006 تغییر دهیم. شما می توانید هر عدد دلخواه را برای شماره پورت در نظر بگیرید.
22- نحوه دریافت مقدار input:
به منظور دریافت مقدار input در ریکت، لازم است برای آن input متد onChange تعریف شود.
function App() { const [name, setName] = useState(" "); const handleInput = event => { setName(event.target.value); }; const logValue = () => { console.log(name); }; return ( <div> <input onChange={handleInput} placeholder="Enter name"/> <button onClick={logValue}>Log value</button> </div> ); }
در کد بالا، مقدار تایپ شده در input در state بنام name ذخیره می شود و سپس با کلیک روی دکمه Log Value ، مقدار name چاپ می شود.
23- نحوه آپدیت state در متد setState:
فرض کنید آبجکت state ما بصورت زیر باشد:
state = { user: { name: "John", age: 19, active: true } };
حالا می خواهیم این state را آپدیت کنیم. توسط متد setState. کد زیر را خواهیم داشت:
class App extends Component { state = { user: { name: "John", age: 19, active: true } }; handleAge = () => { this.setState({ user: { ...this.state.user, age: 29 } }); }; render() { const { name, age } = this.state.user; return ( <div> <p>{name}</p> <p>{age}</p> <button onClick={this.handleAge}>Update age</button> </div> ); } } export default App;
توسط spread operator آبجکت قبلی را با مقادیر قبلی در آبجکت جدید کپی کردیم و فقط فیلد age را تغییر دادیم. یعنی فیلدهای name و active مربوط به user بدون تغییر باقی خواهند ماند.
24- نحوه ارسال props به route component:
فرض کنید کامپوننت Home به صورت زیر باشد:
import React from 'react'; function Home(props){ return ( <div> <p>{props.name}</p> <p>This is home page</p> </div> ) } export default Home;
حالا می خواهیم name را به شکل props و از طریق react router به کامپوننت Home ارسال کنیم. در نسخه 5 ریکت روتر، می توان کامپوننت موردنظر را در کامپوننت Route احاطه (wrap) کرد و props موردنظر را به Home ارسال کرد. کد زیر:
<Route path="/"> <Home name="Ehsan" /> </Route>
شبیه کد بالا، می توان کامپوننت Home را به شکل children تعریف کرد:
<Route path="/" children={ <Home name="Ehsan" />} />
در React Router v4 می توان از render props استفاده کرد:
<Route path="/" render={() => <Home name="Ehsan" />} />
25- نحوه استفاده از متد setInterval:
در این بخش می خواهیم نحوه استفاده از setInterval را در دو نوع فانکشن کامپوننت و کلاس کامپوننت آموزش دهیم. کار متد setInterval انجام کاری در بازه های زمانی مشخص است. مثلا هر 3 ثانیه یکبار، یک پیغام را نمایش دهد. مثال:
setInterval(() => { console.log('you can see me every 3 seconds') }, 3000);
استفاده از setInterval در فانکشن کامپوننت:
در کد زیر متد setInterval را در متد useEffect تعریف کرده ایم:
import React, { useEffect, useState } from "react"; export default function App() { const [seconds, setSeconds] = useState(1); useEffect(() => { const timer = setInterval(() => { setSeconds(seconds + 1); }, 1000); // clearing interval return () => clearInterval(timer); }); return ( <div className="App"> <h1>Number of seconds is {seconds}</h1> </div> ); }
متد useEffect هر زمان که کامپوننت در DOM رندر شد و Mount شد، متد setInterval را صدا می زند. useEffect در این مثال شبیه متد componentDidMount در کلاس کامپوننت عمل می کند.
استفاده از setInterval در کلاس کامپوننت:
در مثال زیر نحوه پیاده سازی setInterval را در کلاس کامپوننت مشاهده می کنیم:
import React from "react"; class App extends React.Component { state = { seconds: 1 }; componentDidMount() { this.timer = setInterval(() => { this.setState({ seconds: this.state.seconds + 1 }); }, 1000); } componentWillUnMount() { clearInterval(this.timer); } render() { return ( <div className="App"> <h1>Number of seconds is {this.state.seconds}</h1> </div> ); } } export default App;
در کد بالا، در هر ثانیه یک واحد به مقدار seconds اضافه می شود.
26- نحوه رفرش صفحه در ریکت:
جهت refresh شدن صفحه یا کامپوننت در ریکت، نیاز به window.location.reload داریم. در حالت پیش فرض، متد reload صفحه را بر اساس کش (cache) رفرش می کند و اگر مقدار true در مقابل reload نوشته شود یعنی reload(true) کل صفحه از سرور ریلود می شود.
در مثال زیر، صفحه اپلیکیشن با کلیک روی دکمه Reload رفرش می شود:
import React from "react"; function Home() { const refreshPage = ()=>{ window.location.reload(); } return ( <div> <h1>{Math.random()}</h1> <button onClick={refreshPage}>Refresh</button> </div> ); }
اما اگر نمی خواهید کل صفحه رفرض شود و تنها می خواهید یک کامپوننت مشخص در صفحه رفرش شود، باید متد setState را با آبجکت خالی صدا بزنیم:
import React from "react"; class App extends React.Component { handleRefresh = () => { // by calling this method react re-renders the component this.setState({}); }; render() { return ( <div> <h1>{Math.random()}</h1> <button onClick={this.handleRefresh}>Refresh component</button> </div> ); } } export default App;
کد بالا برای کلاس کامپوننت ها بکار می رود و کد زیر هم برای فانکشن کامپوننت ها، با استفاده از هوک useState:
import React from "react"; function Home() { const [value,setValue] = useState(); const refresh = ()=>{ // it re-renders the component setValue({}); } return ( <div> <p>{Math.random()}</p> <button onClick={refresh}>Refresh component</button> </div> ); }
27- کاربرد callback در state ریکت:
در کلاس کامپوننت ریکت، آپدیت state توسط متد setState انجام می شود. هر زمان که state تغییر کند، کامپوننت یکبار مجددا رندر می شود و UI جدید به کاربر نمایش می یابد:
setState(updater,callback)
به محض اینکه state تغییر کند و یکبار کامپوننت re-render شود، کال بک فانکشن setState اجرا می شود.
استفاده از Callback Function در کلاس کامپوننت:
برای استفاده از تابع کال بک، باید آن را بعنوان آرگومان دوم به متد setState ارسال کنیم. در مثال زیر، در کال بک فانکشن setState یک API Call انجام می گیرد.
import React from "react"; class App extends React.Component { state = { count: 0 }; increment = () => { this.setState( { count: this.state.count + 1 }, this.checkCount // callback ); }; checkCount = () => { if (this.state.count >= 10) { fetch("https://jsonplaceholder.typicode.com/todos/1") .then(response => response.json()) .then(json => console.log(json)); } }; render() { return ( <div className="App"> <p>{this.state.count}</p> <button onClick={this.increment}>increment</button> </div> ); } } export default App;
به محض اینکه مقدار count یکواحد افزایش یابد، تابع checkCount فراخوانی می شود.
استفاده از Callback Function در فانکشن کامپوننت:
در فانکشن کامپوننت ها ما دیگر setState نداریم و بجای آن هوک useState داریم. useState آرگومان دوم ندارد و ما برای تعریف callback function از هوک useEffect استفاده می کنیم.
import React, { useState, useEffect } from "react"; function App() { const [count, setCount] = useState(0); const increment = () => { setCount(count + 1); }; const checkCount = () => { if (count >= 10) { fetch("https://jsonplaceholder.typicode.com/todos/1") .then(response => response.json()) .then(json => console.log(json)); } }; // useEffect hook runs when a count value is changed useEffect(() => { checkCount(); }, [count]); return ( <div className="App"> <p>{count}</p> <button onClick={increment}>increment</button> </div> ); }
آرگومان دوم useEffect یعنی dependency آن، را برابر count تعریف می کنیم. یعنی هر زمان که count تغییر کرد (state آن آپدیت شد)، دستورات داخل useEffect اجرا شود.
28- نحوه استفاده از تابع setTimeout:
در این بخش می خواهیم چگونگی استفاده از تابع setTimeout را در هوک های ریکت با ذکر مثال آموزش دهیم. تابع setTimeout برای زمانی بکار می رود که می خواهیم کاری را پس از گذشت مدت زمان مشخصی اجرا کنیم. مثلا نمایش یک پیغام پس از 3 ثانیه.
setTimeout(() => { console.log('you can see me after 2 seconds') }, 2000);
استفاده از setTimeout در هوک های ریکت درست مشابه جاوا اسکریپت است. در مثال زیر می خواهیم از این تابع در هوک useEffect استفاده کنیم.
import React, { useState, useEffect } from "react"; export default function App() { const [count, setCount] = useState(0); useEffect(() => { const timeout = setTimeout(() => { setCount(1); }, 3000); },[]); return ( <div className="App"> <h1>{count}</h1> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }
در مثال بالا گفتیم که پس از 3000 میلی ثانیه (3 ثانیه) مقدار count از 0 به 1 تغییر پیدا کند.
29- رندر شرطی یا Conditional Rendering:
رندر شرطی یک المان به این معناست که می خواهیم نمایش/عدم نمایش یک المان بر اساس یک شرط خاص انجام شود. ابتدا نگاهی به بلاک شرطی if-else بیاندازیم:
let num = 2 if(num === 2){ console.log('the given number is 2') }else{ console.log('the give number is not 2') }
حالا می خواهیم نحوه اجرای آن را در کدهای ریکت بررسی کنیم:
function App(props){ if(props.num === 2){ return <p>The given number is 2</p> }else{ return <p>The given number is not 2</p> } } <App num = {2} />
بررسی شرط را می توان با استفاده از Ternary Operator نیز انجام داد.
function App(props){ {props.num === 2 ? <p>The given number is 2</p> : <p>The given number is not 2</p> } } <App num = {2} />
روش دیگر برای بررسی شرط رندر، Logical && می باشد:
function Search(props){ return ( <div> <h1>Search</h1> <button>Search</button> {props.searchResults > 0 && <ul>search results</ul>} </div> ) }
در شرط A && B می گوییم: هر زمان که شرط سمت چپ && برقرار باشد، المان سمت راست در UI رندر می شود.
30- نحوه کار با هوک useHistory:
با کمک هوک useHistory می توان به آبجکت history دسترسی داشت. این آبجکت می تواند به ما در جابجایی بین مسیرهای مختلف اپلیکیشن (Routes) کمک کند. بعنوان مثال:
import React from "react"; import { useHistory } from "react-router-dom"; export default function App() { const history = useHistory(); function navigateToHome() { history.push("/"); } return ( <div className="App"> <h1>Hello react</h1> <button onClick={navigateToHome}>Home</button> </div> ); }
در مثال فوق، ابتدا هوک useHistory را از کتابخانه react-router-dom ایمپورت کردیم و سپس با اجرای useHistory توانستیم به آبجکت history دسترسی داشته باشیم. در ادامه از تابع navigateToHome برای تغییر مسیر به Home استفاده کرده ایم.
31- پیاده سازی Data Binding دو طرفه:
در این بخش می خواهیم نحوه پیاده سازی اتصال دو طرفه (Two way data binding) را با استفاده از هوک های ریکت آموزش دهیم. به کد زیر توجه کنید:
import React,{useState} "react"; function App(){ const [name,setName] = useState(''); const handleChange = (e)=>{ setName(e.target.value); } return ( <div> <input onChange={handleChange} value={name} /> <h1>{name}</h1> </div> ) } export default App;
در مثال فوق، در رویداد onChange مربوط به input ، مقدار state آپدیت می شود. و همچنین زمانیکه name تغییر کند مقدار input هم تغییر می کند. پس توانستیم binding دو طرفه را اجرا کنیم.
32- نحوه focus روی input در ریکت:
می خواهیم وقتی یک کامپوننت رندر می شود، بطور پیش فرض یک input خاص فعال باشد، یعنی بتوان در input تایپ کرد و نیاز نباشد بطور دستی ابتدا داخل input کلیک کنیم و سپس تایپ را انجام دهیم.
در کلاس کامپوننت متدی داریم بنام ComponentDidMount. این متد بلافاصله پس از Mount شدن کامپوننت در DOM اجرا می شود. یعنی اولین متد پس از رندر شدن کامپوننت، این متد می باشد. در فانکشن کامپوننت هم متد useEffect اینکار را انجام می دهد.
بنابراین در کلاس کامپوننت داریم:
import React,{Component} from 'react'; class App extends Component { componentDidMount() { this.searchInput.focus(); } render() { return ( <div> <label>Search </label> <input ref={inputEl => (this.searchInput = inputEl)} /> </div> ); } }
و در فانکشن کامپوننت داریم:
import React, { useEffect, useRef } from "react"; function App() { const searchInput = useRef(null); useEffect(()=>{ // current property is refered to input element searchInput.current.focus(); },[]) return ( <div> <label>Search </label> <input ref={searchInput} /> </div> ); }
و اگر بخواهیم focus روی input با کلیک یک دکمه فعال شود، کد زیر را خواهیم داشت:
import React, { useEffect, useRef } from "react"; function App() { const searchInput = useRef(null) function handleFocus(){ searchInput.current.focus() } return ( <div> <label>Search </label> <input ref={searchInput} /> <button onClick={handleFocus}>Set focus</button> </div> ); }
33- نحوه آنالیز Bundle size در اپ ریکت:
در این بخش می خواهیم نحوه آنالیز سایز bundle را اپلیکیشن ری اکت آموزش دهیم. توسط پکیج source-map-explorer می توان این آنالیز را انجام داد.
نصب source-map-explorer:
npm i source-map-explorer
این پکیج به ما کمک می کند تا سایز باندل فایلهای جاوا اسکریپتی را با استفاده از Source Map بدست آوریم. در مرحله بعد باید فایل package.json را باز کرده و اسکریپت زیر را در آبجکت scripts اضافه کنیم:
"analyze": "source-map-explorer 'build/static/js/*.js'",
سپس با اجرای دستورات زیر می توان باندل های پروژه را آنالیز کرد:
npm run build npm run analyze
34- نحوه استفاده از HTTPS در create-react-app:
در این بخش می خواهیم نحوه اجرای پروژه ری اکتی را با استفاده از HTTPS (بجای HTTP) بررسی کنیم. به دو روش می توان HTTP را به HTTPS تبدیل کرد.
متغیرهای Environment:
باید اسکریپت زیر را در environment variables (قبل از دستور npm start) اضافه کنید:
HTTPS=true npm start
فایل package.json:
این فایل را باز کنید و مقدار start را مطابق دستور زیر تعریف کنید:
{ "start": "HTTPS=true react-scripts start" }
35- نحوه استفاده از radio button:
وقتی از radio button در فرم استفاده می کنیم می خواهیم فقط یک گزینه از بین تمام گزینه ها قابل انتخاب باشد. برای کار با radio button در React نیاز به تعریف اتریبیوت name و رویداد onChange در radio-input می باشد.
کد زیر را برای کلاس کامپوننت در نظر بگیرید:
import React,{Component} from 'react'; class App extends Component { state = { gender:"" }; handleChange=(e)=>{ this.setState({ gender: e.target.value }) } render() { return ( <div> <form> <input type="radio" value="male" id="male" onChange={this.handleChange} name="gender" /> <label for="male">Male</label> <input type="radio" value="female" id="female" onChange={this.handleChange} name="gender"/> <label for="female">Female</label> </form> <p>You gender is --> {this.state.gender}</p> </div> ); } }
مشاهده می شود که با استفاده از name یکسان، یک radio group ایجاد کردیم که فقط می توان یکی از آنها را در هر لحظه انتخاب کرد.
کد زیر را برای فانکشن کامپوننت در نظر بگیرید:
import React, { useState } from 'react'; function App() { const [gender,setGender]=useState(''); const handleChange=(e)=>{ setGender( e.target.value); } return ( <div> <form> <input type="radio" value="male" id="male" onChange={handleChange} name="gender" /> <label for="male">Male</label> <input type="radio" value="female" id="female" onChange={handleChange} name="gender"/> <label for="female">Female</label> </form> <p>You gender is --> {gender}</p> </div> ); }
36- تفاوت بین state و props:
ویژگی های state:
- برای ذخیره داده های مختص هر کامپوننت بکار می رود. این داده ها در هر کامپوننت private هستند.
- مقدار state قابل تغییر است.
- برای آپدیت state در کلاس کامپوننت از this.setState و در فانکشن کامپوننت از useState استفاده می شود.
- به محض آپدیت شدن state کامپوننت re-render می شود.
import React, { Component } from "react"; class Counter extends Component { // state is initialzed with count value 0 state = { count: 0 }; handleIncrement = () => { //updating count value this.setState({ count: this.state.count + 1 }); }; render() { return ( <div> <h1>{count}</h1> <button onClick={handleIncrement}>Increment</button> </div> ); } } export default Counter;
ویژگی های props:
- props برای انتقال داده بین کامپوننت parent و child بکار می رود.
- props اصلا قابل تغییر و آپدیت نیستند.
import React, { Component } from "react"; import Welcome from "./Welcome"; class App extends Component { state = { msg: "Welcome to react" }; render() { return ( <div> <h1>Learning react</h1> // passing message prop to the Welcome component <Welcome messsage={this.state.msg} /> </div> ); } } export default App;
37- نحوه تغییر route به صورت داینامیک:
در فانکشن کامپوننت می توان با استفاده از هوک useHistory بطور داینامیک کاربر را به route های مختلف فرستاد. به مثال زیر توجه کنید:
import React from 'react'; import { useHistory } from "react-router-dom"; function HomeButton() { const history = useHistory(); function handleClick() { history.push("/home"); } return ( <button type="button" onClick={handleClick}> Go to home </button> ); }
مشاهده می شود که ابتدا useHistory را از کتابخانه react-router-dom ایمپورت کردیم و توسط متد push به مسیر دلخواه navigate کرده ایم.
و در کلاس کامپوننت کد زیر را خواهیم داشت:
import React,{Component} from 'react'; class App extends Component{ gotoHome = () => { this.props.history.push('/') } render() { return ( <div> <button onClick={this.gotoHome}>Home</button> </div> ) } } export default App;
38- نحوه نمایش پیغام های Toast:
بهترین کتابخانه برای نمایش پیغام های Toast لایبرری React Toastify می باشد. برای نصب این لایبرری محبوب، دستور زیر را در ترمینال اجرا کنید:
npm i react-toastify
نحوه پیاده سازی Toastify در یک کامپوننت به صورت زیر است:
import React from "react"; import { ToastContainer, toast } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; function App() { function Notify() { toast("You clicked the button"); } return ( <div className="App"> <ToastContainer /> <button onClick={Notify}>Run toast</button> </div> ); } export default App;
مشاهده می کنید که باید فایل css مربوط به لایبرری یعنی ReactToastify.css را ایمپورت کنیم. در موقع فراخوانی متد toast باید پیغام موردنظر را بعنوان آرگومان این متد ارسال کرد. برای تغییر موقعیت نمایش پیغام، بصورت زیر عمل کنید:
function Notify() { toast("You clicked the button",{ //toast is positioned on bottom right position: "bottom-right" }); }
در واقع بعنوان آرگومان دوم تابع toast، می توان یک آبجکت پاس داد که موقعیت نمایش Toast را در آن تعریف کرد. این موقعیت می تواند یکی از موارد زیر باشد:
top-right, top-center, top-left bottom-right, bottom-center, bottom-left
برای تعیین مدت زمان نمایش پیغام به کاربر، می توان به شکل زیر عمل کرد:
function Notify() { toast("You clicked the button",{ position: "bottom-right", //toast will be closed after 10 seconds autoClose: 10000 }); }
یعنی بعنوان آیتم دوم از آبجکت تنظیمات Toastify مدت زمان نمایش پیغام را به میلی ثانیه پاس می دهیم.
خروجی به شکل زیر خواهد بود:
39- نحوه کار با styled-components:
کتابخانه styled-component این امکان را به توسعه دهنده ریکت می دهد که به جای تعریف استایل های CSS در فایل جدا، در داخل کدهای جاوا اسکریپت CSS را تعریف کند. این لایبرری به المان های مختلف، کلاس های رندوم می دهد. پس نیازی نیست نگران تداخل نام های یکسان با یکدیگر باشید.
نصب پکیج Styled-Components:
اجرای دستور زیر در ترمینال:
npm install styled-components
و استفاده از آن در کامپوننت به شکل زیر:
import React, { Component } from 'react'; import styled from 'styled-components' const Mydiv = styled.div` display:flex; justify-content:center; align-items:center; background-color: #cccc; height: 100vh; ` class App extends Component { render() { return ( <Mydiv> <h1>Hello styled components</h1> </Mydiv> ); } } export default App;
خروجی کار به صورت زیر خواهد بود:
40- نحوه اجرای حلقه روی آرایه/لیست:
فرض کنید آرایه زیر را داریم و می خواهیم آیتم های آن را در مرورگر نمایش دهیم:
const users = [ {id:1,name:"local"}, {id:2,name:"kid"}, {id:3,name:"king"}, ]
به شکل زیر می توان توسط متد map روی آرایه حلقه اجرا کرد:
function Users(){ return( <ul> {users.map((user)=><User key={user.id} name={user.name}/>)} </ul> ) }
بخش دوم از ترفندهای طلایی ری اکت به پایان رسید. در بخش سوم، 20 مورد دیگر از نکات و ترفندهای طلایی ReactJS را بررسی خواهیم کرد.
دیدگاهتان را بنویسید