قرار دادن داده ها بطور مستقیم در داخل برنامه کار خوبی نیست. در این آموزش ما قابلیت کار با داده ها را به برنامه مان اضافه می کنیم تا برنامه به راحتی بتواند به داده های خارجی دسترسی داشته باشد.
تا به اینجای آموزش ما اولین کامپوننت مان را نوشتیم و رابطه فرزند/والد را هم برای آن تنظیم کردیم. اما این کامپوننت هنوز از داده ها استفاده نمی کند. بنابراین این برنامه نمی تواند از قدرت ری اکت برای نمایش داده های داینامیک یا پویا استفاده کند. در این آموزش قصد افزودن قابلیت کار با داده ها در ری اکت را داریم.
اگر به یاد داشته باشید در آموزش قبلی دیدید که ما یک کامپوننت timeline که شامل یک هدر و یک لیستی از فعالیت (اکتیویتی)های مختلف بود، را نوشته ایم
همچنین این برنامه را به سه کامپوننت مجزا که هر کدام قالب های jsx استاتیکی داشتند، تقسیم کردیم. اما هر زمانی که بخواهیم تغییری را در وب سایت ایجاد کنیم، بروزرسانی این کامپوننت ها کار راحتی نخواهد بود.
در این آموزش می خواهیم از این کامپوننت ها برای نمایش داده استفاده کنیم. بنابراین از کامپوننت <Header/> استفاده می کنیم.
همان طور که مشخص است کامپوننت <Header/> فقط عنوان کامپوننت timeline را نمایش می دهد. این یک عنصر خیلی مفیدی است، چون می توانیم از آن در قسمت های مختلف برنامه مان استفاده کنیم، اما مشکلی که وجود دارد این است که هر کامپوننت timeline باید عنوان های مختلفی داشته باشد.
حال باید به ری اکت بگوییم که هر کدام از این کامپوننت های timeline باید عنوان های مختص به خود را داشته باشند.
ری اکت به ما اجازه می دهد تا به همان طریقی که به یک عنصر html داده ای را ارسال می کنیم، به کامپوننت ری اکت هم توسط خصیصه یا پروپرتی داده ای را ارسال کنیم.
اینکار مشابه خصیصه src برای یک تگ تصویر است. ما می توانیم به پروپرتی های تگی مانند <img> همانند یک prop نگاه کنیم که به کامپوننت های ری اکت اعمال می شود.
همچنین برای دسترسی به مقادیر این پروپرتی ها در داخل کامپوننت از this.props استفاده می کنیم. در آموزش های قبلی، کامپوننت <Header/> را مانند زیر تعریف کردیم.
lass Header extends React.Component { render() { return ( <div className="header"> <div className="menuIcon"> <div className="dashTop"></div> <div className="dashBottom"></div> <div className="circle"></div> </div> <span className="title"> {this.props.title} </span> <input type="text" className="searchInput" placeholder="Search ..." /> <div className="fa fa-search searchIcon"></div> </div> ) } }
هنگام استفاده از کامپوننت <Header/> آن را داخل کامپوننت <App/> مانند زیر قرار می دهیم.
<Header />
حال می توانیم عنوان هر هدر را توسط پروپرتی title به کامپوننت <Header/> ارسال کنیم.
<Header title="Timeline" />
برای دسترسی به مقدار این پروپرتی در داخل کامپوننت از this.props استفاده می کنیم. حال به جای اینکه مقدار عنوان هدر را بصورت استاتیک تعریف کنیم، می توانیم به صورت داینامیک یا پویا عنوان هدرها را مشخص کنیم.
import React from 'react' class Header extends React.Component { render() { return ( <div className="header"> <div className="menuIcon"> <div className="dashTop"></div> <div className="dashBottom"></div> <div className="circle"></div> </div> <span className="title"> {this.props.title} </span> <input type="text" className="searchInput" placeholder="Search ..." /> <div className="fa fa-search searchIcon"></div> </div> ) } } export default Header
در بالا کدهای کامپوننت <Header/> را کمی تغییر دادیم تا کارهای خواسته شده را بهتر انجام دهد. همچنین یک کلاس searchIcon و menuIcon هم برای استایل دهی به این کامپوننت اضافه کردیم.
حال هنگام فراخوانی کامپوننت <Header/> می توانیم توسط پروپرتی title، یک عنوان را به کامپوننت ارسال کنیم تا در برنامه نمایش داده شوند. برای مثال می توانیم کامپوننت <Header/> را مانند زیر فراخوانی کنیم.
<Header title="Timeline" /> <Header title="Profile" /> <Header title="Settings" /> <Header title="Chat" />
نتیجه اجرا شامل چهار کامپوننت مانند زیر است که هر کدام عنوان های متفاوتی دارد.
حال می توانیم از کامپوننت <Header/> که یک پروپرتی داینامیک یا پویا به نام title دارد در قسمت های مختلف برنامه استفاده کنیم.
همچنین می توانیم به جز نوع داده رشته ای، انواع دیگری هم به کامپوننت ارسال کنیم، مانند اعداد، رشته، آبجکت ها و حتی توابع.
به جای اینکه محتوا و تاریخ را در کامپوننت بصورت استاتیک تنظیم کنیم، می توانیم یک پروپرتی به نام content تعریف کرده و در زمان فراخوانی کامپوننت، محتوای مورد نظرمان را به این پروپرتی ارسال کنیم.
همانند عناصر html، کامپوننت های ری اکت هم می توانند چندین پروپرتی داشته باشند. در آموزش قبلی ،کامپوننت content را به شکل زیر تعریف کردیم:
class Content extends React.Component { render() { return ( <div className="content"> <div className="line"></div> {/* Timeline item */} <div className="item"> <div className="avatar"> <img src="http://www.croop.cl/UI/twitter/images/doug.jpg" /> Doug </div> <span className="time"> An hour ago </span> <p>Ate lunch</p> <div className="commentCount"> 2 </div> </div> {/* ... */} </div> ) } }
پروپرتی های کامپوننت محتوا نیاز به موارد زیر دارند:
حال فرض کنید که یک آبجکت جاوا اسکریپت دارید که یک آیتم اکتیویتی را نمایش می دهد. ما چند فیلد از قبیل فیلد متنی و یک آبجکت date داریم. همچنین چند آبجکت دیگر از قبیل user و comment هم داریم.
برای مثال:
{ timestamp: new Date().getTime(), text: "Ate lunch", user: { id: 1, name: 'Nate', avatar: "http://www.croop.cl/UI/twitter/images/doug.jpg" }, comments: [ { from: 'Ari', text: 'Me too!' } ] }
مشابه یک مقدار رشته ای که به کامپوننت <Header/> پاس دادیم، می توانیم این آبجکت اکتیویتی را گرفته و آن را به کامپوننت content پاس دهیم. حال کامپوننت مان را برای نمایش جزئیات این اکتیویتی در داخل قالب تغییر می دهیم.
به علاوه برای ارسال مقدار یک متغیر داینامیک یا پویا به داخل قالب باید از سینتکس قالب (template syntax) برای رندر آن در داخل قالب برنامه استفاده کنیم. برای نمونه:
import React from 'react' class Content extends React.Component { render() { const {activity} = this.props; // ES6 destructuring return ( <div className="content"> <div className="line"></div> {/* Timeline item */} <div className="item"> <div className="avatar"> <img alt={activity.text} src={activity.user.avatar} /> {activity.user.name} </div> <span className="time"> {activity.timestamp} </span> <p>{activity.text}</p> <div className="commentCount"> {activity.comments.length} </div> </div> </div> ) } } export default Content
در اولین خط تابع render از یک کد ES6 به نام destructuring استفاده کردیم.
دو خط زیر دقیقا معادل هم هستند.
// these lines do the same thing const activity = this.props.activity; const {activity} = this.props;
destructuring به ما اجازه می دهد تا تعریف متغیرها را به روش کوتاه تری انجام دهیم. سپس با ارسال یک آبجکت به عنوان پروپرتی می توانیم از این محتوای جدید استفاده کنیم.
<Content activity={moment1} />
بسیار خوب، حالا اکتیویتی هایی داریم که از یک آبجکت مشتق شده اند.
با این حال، ممکن است دیده باشید که ما این کامپوننت ها را چندین بار با نظرات مختلف پیاده سازی کرده ایم. در عوض ما می توانیم یک آرایه ای از آبجکت ها را به داخل کامپوننت ارسال کنیم.
فرض کنید یک آبجکت داریم که شامل چندین آیتم اکتیویتی است:
const activities = [ { timestamp: new Date().getTime(), text: "Ate lunch", user: { id: 1, name: 'Nate', avatar: "http://www.croop.cl/UI/twitter/images/doug.jpg" }, comments: [{ from: 'Ari', text: 'Me too!' }] }, { timestamp: new Date().getTime(), text: "Woke up early for a beautiful run", user: { id: 2, name: 'Ari', avatar: "http://www.croop.cl/UI/twitter/images/doug.jpg" }, comments: [{ from: 'Nate', text: 'I am so jealous' }] }, ]
همچنین می توانید با ارسال چند اکتیویتی بصورت همزمان به کامپوننت <Content/> محتواهای بیشتری ایجاد کنید.
<Content activities={activities} />
حال اگر صفحه را رفرش کنید، چیزی را مشاهده نخواهید کرد، چون ابتدا باید کامپوننت content را بروزرسانی کنیم تا بتواند چندین اکتیویتی را دریافت کند. همان طور که قبلاً یاد گرفتید، jsx در واقع همان جاوا اسکریپت است که توسط مرورگر اجرا می شود. ما می توانیم توابع جاوا اسکریپت را داخل jsx اجرا کنیم، چون این کدهای jsx همانند سایر کدهای جاوا اسکریپت در مرورگر اجرا می شود. حال باید کدهای jsx اکتیویتی را به داخل تابع map که به ازای هر آیتم یکبار اجرا می شود، منتقل کنیم.
import React from 'react' class Content extends React.Component { render() { const {activities} = this.props; // ES6 destructuring return ( <div className="content"> <div className="line"></div> {/* Timeline item */} {activities.map((activity) => { return ( <div className="item"> <div className="avatar"> <img alt={activity.text} src={activity.user.avatar} /> {activity.user.name} </div> <span className="time"> {activity.timestamp} </span> <p>{activity.text}</p> <div className="commentCount"> {activity.comments.length} </div> </div> ); })} </div> ) } } export default Content
حال می توانیم هر تعداد اکتیویتی که خواستیم را به داخل آرایه ارسال کنیم تا کامپوننت content آنها را مدیریت کند.
دراین قسمت یک کامپوننت برای نمایش یک آیتم اکتیویتی ایجاد می کنیم. همچنین به جای نوشتن یک کامپوننت content پیچیده، می خواهیم یک کامپوننت دیگر برای نمایش آیتم های اکتیویتی بوجود بیاوریم تا به این ترتیب واکنش پذیری برنامه بالا برود.
این کار تست برنامه را راحت تر کرده و در آینده می توانیم به راحتی قابلیت های دیگری را به آن اضافه کنیم.
حال کامپوننت content را برای نمایش یک لیستی از کامپوننت های ActivityItem بروزرسانی می کنیم.
import React from 'react' import ActivityItem from './ActivityItem'; class Content extends React.Component { render() { const {activities} = this.props; // ES6 destructuring return ( <div className="content"> <div className="line"></div> {/* Timeline item */} {activities.map((activity) => ( <ActivityItem activity={activity} /> ))} </div> ) } } export default Content
نه تنها این کد ساده تر بوده و به راحتی درک می شود، بلکه به راحتی می توان هر دو کامپوننت را تست کرد.
حال کامپوننت ActivityItem را ایجاد می کنیم. چون ما قبلاً یک view برای ActivityItem ایجاد کرده بودیم، تنها کاری که باید بکنیم این است که آن را از کامپوننت Content کپی کنیم و در یک ماژول مستقل مختص به خودش قرار دهیم.
import React from 'react' class ActivityItem extends React.Component { render() { const {activity} = this.props; // ES6 destructuring return ( <div className="item"> <div className="avatar"> <img alt={activity.text} src={activity.user.avatar} /> {activity.user.name} </div> <span className="time"> {activity.timestamp} </span> <p>{activity.text}</p> <div className="commentCount"> {activity.comments.length} </div> </div> ) } } export default ActivityItem
در این هفته، با کمک props کامپوننت هایمان را داده محور کردیم. در بخش بعدی به کامپوننت های stateful می پردازیم.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.