ری اکت روش های مختلفی را برای ساخت یک کامپوننت پیشنهاد می کند. در این درس درباره آخرین روش ساخت یک کامپوننت با استفاده از کامپوننت های خالص بدون وضعیت (stateless) صحبت می کنیم.
در درس های قبلی روش های مختلف ساخت یک کامپوننت در ری اکت را بررسی کردیم. روشی که در این درس قصد داریم به آن بپردازیم، ساخت کامپوننت های بدون وضعیت در ری اکت است.
تا به اینجای آموزش ما با استفاده از متدهای React.Component
و ()React.createClass
اقدام به ساخت کامپوننت ها می کردیم. ری اکت به منظور کارایی و سادگی بیشتر، امکان ساخت کامپوننت های بدون وضعیت با استفاده از یک تابع معمولی جاوا اسکریپت را فراهم کرده است.
یک کامپوننت خالص می تواند جایگزین یک کامپوننتی شود که تنها یک متد render دارد.
به جای ساخت یک کامپوننت کاملی که مقداری محتوا را در صفحه نمایش رندر می کند، می توانیم از یک کامپوننت خالص استفاده کنیم.
کامپوننت های خالص آسانترین و سریع ترین کامپوننت هایی هستند که ما می توانیم بنویسیم. قبل از اینکه بگوییم چرا این کامپوننت ها بهتر از بقیه هستند، اجازه بدهید یک کامپوننت از این نوع را ایجاد کنیم:
// The simplest one const HelloWorld = () => (<div>Hello world</div>); // A Notification component const Notification = (props) => { const {level, message} = props; const classNames = ['alert', 'alert-' + level] return ( <div className={classNames}> {message} </div> ) }; // In ES5 var ListItem = function(props) { var handleClick = function(event) { props.onClick(event); }; return ( <div className="list"> <a href="#" onClick={handleClick}> {props.children} </a> </div> ) }
همان طور که می بینید این کامپوننت ها صرفا یک تابع هستند، بنابراین به راحتی توسط جاوا اسکریپت می شود آنها را تست کرد.
props های مشابه، خروجی های DOM مجازی مشابهی هم دارند.
در ری اکت، کامپوننت های تابعی توسط یک آرگومان به نام props فراخوانی می شوند (مشابه کلاس سازنده در React.Component) و این propsها با context کامپوننت جاری فراخوانی می شود.
برای مثال، فرض کنید که می خواهیم کامپوننت Timer را با استفاده از کامپوننت های تابعی بازنویسی کنیم و به کاربران این امکان را بدهیم تا بتوانند استایل ساعت شان را بطور دینامیک مشخص کنند. (مثلاً زمان 12 یا 24 ساعته، جداکننده های مختلف، امکان عدم نمایش ثانیه و ...)
حال می خواهیم کامپوننت های clock را به چند کامپوننت دیگر تقسیم کنیم. بنابراین هر بلوک زمانی را در یک کامپوننت مستقل ایجاد خواهیم کرد. مطابق زیر:
const Hour = (props) => { let {hours} = props; if (hours === 0) { hours = 12; } if (props.twelveHours) { hours -= 12; } return (<span>{hours}</span>) }
const Minute = ({minutes}) => (<span>{minutes<10 && '0'}{minutes}</span>)
const Second = ({seconds}) => (<span>{seconds<10 && '0'}{seconds}</span>)
const Separator = ({separator}) => (<span>{separator || ':'}</span>)
const Ampm = ({hours}) => (<span>{hours >= 12 ? 'pm' : 'am'}</span>)
حال می توانیم به جای استفاده از کامپوننت Clock از این کامپوننت های مجزا استفاده کنیم:
<div>Minute: <Minute minutes={12} /></div> <div>Second: <Second seconds={51} /></div>
کامپوننت clock را تغییر می دهیم تا بتواند یک رشته متنی را دریافت کند، و توسط این رشته بتوانیم تنها آن زمان های دلخواه (ساعت، دقیقه و ... ) را نمایش دهیم. چندین روش برای انجام اینکار وجود دارد، مثلاً اجرای کد در داخل کامپوننت clock و یا ایجاد یک کامپوننت بدون وضعیت دیگر که یک رشته متنی را دریافت کند.
const Formatter = (props) => { let children = props.format.split('').map((e, idx) => { if (e === 'h') { return <Hour key={idx} {...props} /> } else if (e === 'm') { return <Minute key={idx} {...props} /> } else if (e === 's') { return <Second key={idx} {...props} /> } else if (e === 'p') { return <Ampm key={idx} {...props} /> } else if (e === ' ') { return <span key={idx}> </span>; } else { return <Separator key={idx} {...props} /> } }); return <span>{children}</span>; }
کد بالا به دلیل استفاده از key و {… props} ظاهر مناسبی ندارد. ری اکت تعدادی helper برای کار با کامپوننت های فرزند و مدیریت key منحصر به فرد مربوط به هر عنصر فرزند از طریق آبجکت React.Children، برای ما فراهم کرده است.
تابع render() در کامپوننت clock به دلیل استفاده از کامپوننت formatter خیلی ساده تر شده است.
class Clock extends React.Component { state = { currentTime: new Date() } componentDidMount() { this.setState({ currentTime: new Date() }, this.updateTime); } componentWillUnmount() { if (this.timerId) { clearTimeout(this.timerId) } } updateTime = e => { this.timerId = setTimeout(() => { this.setState({ currentTime: new Date() }, this.updateTime); }) } render() { const { currentTime } = this.state const hour = currentTime.getHours(); const minute = currentTime.getMinutes(); const second = currentTime.getSeconds(); return ( <div className='clock'> <Formatter {...this.props} state={this.state} hours={hour} minutes={minute} seconds={second} /> </div> ) } }
حال نه تنها کامپوننت clockساده تر شد، بلکه براحتی می شود از این کامپوننت تست گرفت. همچنین به ما کمک می کند تا بتوانیم به راحتی به فریمورک های مدیریت وضعیت مثل Flux/Redux نرم افزارهای خود را طراحی کنیم.
مزایای استفاده از کامپوننت های تابعی در ری اکت به شرح زیر است:
احتمالاً با خود می گویید، پس چرا نباید همیشه از کامپوننت های تابعی استفاده کنم؟
در زیر تعدادی از معایب کامپوننت های تابعی را آورده ایم:
در کل استفاده از کامپوننت های تابعی نسبت به کامپوننت های سنگین تر مثل React.Component توصیه می شود.
به این ترتیب تا به امروز سه روش ساخت کامپوننت در ری اکت را بررسی کردیم.
در درس بعدی به روش ساخت برنامه های ری اکت توسط create-react-app که یک ابزار مدیریت پکیج بوده و توسط تیم ری اکت توسعه پیدا کرده است، می پردازیم.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.