مطالب
راه اندازی StimulSoft Report در ASP.NET MVC
یکی از ارکان لاینفک سیستم‌های سازمانی در هر پلتفرمی، چه وب و چه دسکتاپ و ... گزارش گیری از اطلاعات موجود و جزو ساختار حیاتی آن است. از آنجا که حتی ممکن است این گزارشات در هر دوره نیاز به تغییرات داشته باشند و گزارش‌های پویایی باشند؛ این نیاز احساس می‌شود که از یک برنامه گزارش ساز مناسب بهره ببریم. یکی از گزارش سازهای محبوب به خصوص در ایران که حتی نماینده رسمی آن هم در ایران وجود دارد، گزارش ساز StimulSoft Report است.

دارا بودن امکانات بسیار قدرتمند و پشتیبانی از محیط فارسی و همچنین پشتیبانی آن‌ها جهت پاسخگویی به سوالات، چه از طریق ایمیل یا چت، از نقاط قوت این ابزار به شمار می‌روند. در جدول مقایسات می‌توانید تفاوت نسخه‌های موجود این گزارش ساز را مشاهده کنید. برای استفاده در MVC از نسخه وب آن استفاده میکنیم.

در این مقاله قصد داریم با نحوه راه ندازی این ابزار در وب (MVC) آشنا شویم که شامل مباحث زیر می‌شود:
  1. استفاده از EF به عنوان منبع داده و ارسال آن‌ها به سمت گزارش ساز
  2. نحوه طراحی فایل MRT و بایند کردن داده‌های اطلاعاتی و ایجاد جدول
  3. استفاده از امکانات فایل خروجی ، چاپ و پیش نمایش و...
  4. بررسی Direction جهت استفاده در محیط‌های فارسی زبان
  5. نحوه ارسال اطلاعات بین دو اکشن متفاوت


طراحی فایل MRT

فایل MRT در واقع یک قالب (Template) خالی از مقادیر متغیر است که در StimulSoft Studio به طراحی آن میپردازیم و در برنامه خود، این مقادیر متغیر را با اطلاعات دلخواه خود جایگزین می‌کنیم. تصویر زیر یک نمونه از یک گزارش خالی است که ابتدا آن را طراحی کرده و سپس در برنامه آن را مورد استفاده قرار می‌دهیم:

برای اینکه فایل MRT بتواند دیتاهای لازمی را که به آن پاس میدهیم، بخواند و در جای مشخص شده قرار بدهد، باید یک BussinessObject برای آن ایجاد کنیم. بعد از اینکه یک گزارش جدید ایجاد کردید، در سمت راست به قسمت Dictionary بروید و در قسمت BussinessObject گزینه NewBussinessObject را انتخاب کنید. یک نام و نام مستعار که عموما هم یکی است، برای آن انتخاب کنید. در زیر همان پنجره شما می‌توانید ستون‌های اطلاعاتی خود را تعریف کنید. در اینجا من میخواهم اطلاعات یک راننده را به همراه خودروی وی، نشان دهم. برای همین، من دو موجودیت راننده و خودروی راننده را دارم. پس اسم Business Object را DriverReport میگذارم و ستون‌های اطلاعاتی فقط راننده (بدون در نظر گرفتن خودروی وی) را وارد میکنم.

در همین کادر بالا شما میتوانید تصیم بگیرید که آیا میخواهید اطلاعات خودرو را به همراه دیگرستون‌های اطلاعاتی راننده، ایجاد کنید یا اینکه برای خودرو یک نوع مجزا انتخاب کنید. اگر تنها یک خودرو برای راننده باشد، شاید راحت‌تر باشید همانند اطلاعات راننده با آن رفتار کنید. ولی اگر مثلا بخواهید خودروی‌های گذشته راننده را هم جز لیست داشته باشید، بهتر است یک  Business Object جدید متعلق و زیر مجموعه Business Object راننده ایجاد کنید. در اینجا چون تنها یک خودرو است، من آن اطلاعات آن را به همراه راننده، ارسال میکنم. شکل زیر ساختار درختی از گزارش بالاست:

شکل زیر هم یک ساختار دیگر از یک گزارش است که شامل Business object‌های مختلف می‌شود: 

سپس همین فیلدها را به سمت صفحه خالی بکشانید. با دو بار کلیک روی فیلدهای قرار گرفته در صفحه، با نحوه بایند کردن مقادیر آشنا می‌شوید؛ هر فیلدی که قرار است دیتای آن بایند شود، باید به شکل زیر در بخش Expression پنجره باز شده، نوشته شود:

{driverReport.LastName}
در صورتیکه قرار است Business Object به شکل یک لیست ارسال شود؛ مثلا لیست رانندگان یا حتی لیست خودروهایی که یک راننده از گذشته تا کنون داشته است، می‌توانید به جای درگ کردن فیلد به درون صفحه، خود Business Object را درگ کنید تا از روی آن یک جدول درست شود و با ارسال یک لیست به سمت آن و به ازای هر آیتم از این لیست یک سطر داشته باشید.

در دیکشنری همچنین انواع دیگری از فیلدها نیز به چشم میخورد:
متغیرها: این نوع فیلد یک متغیر است که به طور جداگانه میتواند مقداردهی شود و از آن بیشتر برای ارسال داده‌های تکی چون تصاویر، تاریخ شمسی و ... میتوان استفاده کرد.
متغیرهای سیستمی: این نوع متغیرها توسط خود گزارش ساز به طور مستقیم پر می‌شوند که شامل شماره صفحه، تاریخ و زمان، تعداد صفحات، مقادیر دو ارزشی (آیا صفحه آخر گزارش است؟) و ... می‌شود.
توابع: گزارش ساز شامل یک سری توابع آماده برای اعمال تغییرات بر روی داده‌ها میباشد که در دسته‌های مختلفی چون کار با رشته‌ها، زمان، ریاضیات و... قرار گرفته‌اند.
بعد از تکمیل آن، فایل MRT را ذخیره و در یک دایرکتوری در ساختار پروژه قرار دهید.

راه اندازی گزارش ساز در ASP.Net MVC

اولین کاری که می‌کنیم، ورود سه dll اصلی به پروژه است:

Stimulate.Base

Stimulate.Report

Stimulate.Report.MVC

در مرحله بعد یک متد ساخته و یک ویوو را برای صفحه گزارش گیری ایجاد می‌کنیم:

public ActionResult Report(int id)
{
   return View();
}
در ویوی مربوطه کدهای زیر را اضافه می‌کنیم:
@Html.Stimulsoft().StiMvcViewer(new StiMvcViewerOptions()
{
   
    Localization = "~/content/reports/fa.xml",
    Actions =
        {
        
            GetReportSnapshot = "LoadReportSnapshot",
            ViewerEvent = "ViewerEvent",
            ExportReport = "ExportReport",
            PrintReport = "PrintReport",
        }
 }

در نسخه‌های دو سال اخیر، استفاده از این Helper تفاوت‌هایی در نحوه استفاده از خصوصیت‌های آن کرده است. در این روش جدید، پراپرتی‌ها دسته بندی شده و برای دسترسی به هر کدام باید به بخش آن مراجعه کنید؛ مثلا پراپرتی‌های Action، در دسته Actions قرار گرفته‌اند یا خصوصیت‌های ظاهری در دسته Appearance، یا گزینه‌های مرتبط با خروجی گرفتن‌ها، در دسته Export قرار گرفته‌اند و الی آخر که در نسخه‌های پیشین، کد بالا را به شکل زیر،  با پیشوند نام دسته می‌نوشتیم:
@Html.Stimulsoft().StiMvcViewer(new StiMvcViewerOptions()
{
   
    Localization = "~/content/reports/fa.xml",
            ActionGetReportSnapshot = "LoadReportSnapshot",
            ActionViewerEvent = "ViewerEvent",
            ActionExportReport = "ExportReport",
            ActionPrintReport = "PrintReport",
            
}
خصوصیت GetReportSnapshot نام یک اکشن متد است که کار ارسال دیتا را به گزارش ساز، انجام میدهد. باقی خصوصیت‌ها را در ادامه بررسی میکنیم. پس متد LoadReportSnapshot را ایجاد می‌کنم و کدهای زیر را در ادامه آن می‌نویسیم:

بعد از آن لازم است دیتا‌ها را از طریق EF خوانده و به یک مدل جدید که بر اساس اطلاعات گزارش شماست و قرار است گزارش شما این پراپرتی‌ها را بشناسد، به طور دستی یا با استفاده یک کتابخانه mapping مثل automapper انتقال دهید. یا حتی می‌توانید مانند کد زیر از ساختاری ناشناس استفاده کنید. در کد زیر، من به صورت تمرینی اطلاعات یک راننده و خودروی او را انتقال میدهم:
var driver = new
            {
                FirstName = "علی",
                LastName = "یگانه مقدم",
                NationalCode = "12500000000",
                FatherName = "حسین",
                Model = "نام خودرو",
                MotorNumber = 415244,
                ProductionYear = 1394,
                Capacity = 4
                
};
اگر اطلاعات خودرو را هم به صورت مجزا BussinessObject ساخته‌اید باید آن را به شکل زیر تعریف کنید ( با فرض اینکه نام BussinessObject در گزارش، با نام car تعریف شده باشد):
var driver = new
            {
                FirstName = "علی",
                LastName = "یگانه مقدم",
                NationalCode = "12500000000",
                FatherName = "حسین",
                car = new
                {
                    Model = "نام خودرو",
                    MotorNumber = 415244,
                    ProductionYear = 1394,
                    Capacity = 4
                }
};
بعد از اینکه دیتاهای لازم را بر اساس فرمت دلخواه خود آماده کردیم، باید آن‌ها را به سمت گزارش ساز ارسال کنیم:
var report = new StiReport();
            report.Load(Server.MapPath("~/Content/Reports/driver.mrt"));
            report.RegBusinessObject("driverReport", driver);
            report.Dictionary.Variables.Add("today", DateTime.Today.ToPersianString(PersianDateTimeFormat.Date));
در مرحله اول یک وهله از شیء StiReport را می‌سازیم و فایل گزارشی را که در مرحله قبل ساختیم، به آن معرفی میکنیم. سپس داده‌های لازم را به آن انتقال می‌دهیم. پارامتر اول نام BussinessObject اصلی یعنی driverReport را وارد می‌کنیم و پارامتر دوم هم، همان اطلاعات گزارش است. خط بعدی هم یک متغیر است که من در گزارش تعریف کرده‌ام و در اینجا آن را با تاریخ شمسی امروز پر میکنم. توجه داشته باشید که انتقال اطلاعات حتما باید بعد از استفاده از متد Load باشد؛ در غیر اینصورت انتقالی انجام نخواهد شد. اینکه صرفا شما وهله‌ای از شیء StiReport بسازید و مقادیر را بدون ترتیب پر کنید، کفایت نمی‌کند. یعنی ترتیب زیر یک ترتیب کاملا اشتباه است:
var report = new StiReport();
            report.RegBusinessObject("driverReport", driver);
            report.Dictionary.Variables.Add("today", DateTime.Today.ToPersianString(PersianDateTimeFormat.Date));
           report.Load(Server.MapPath("~/Content/Reports/driver.mrt"));
چیزی که بعدا در خروجی می‌بینید، یک صفحه گزارش بدون مقدار است.
پس کد کامل ما برای ایجاد یک گزارش به شکل زیر می‌شود:
 public ActionResult LoadReportSnapshot()
{
  var driver = new
            {
                FirstName = "علی",
                LastName = "یگانه مقدم",
                NationalCode = "12500000000",
                FatherName = "حسین",
                Model = "نام خودرو",
                MotorNumber = 415244,
                ProductionYear = 1394,
                Capacity = 4

            };

            var report = new StiReport();
            report.Load(Server.MapPath("~/Content/Reports/driver.mrt"));
            report.RegBusinessObject("driverReport", driver);
            report.Dictionary.Variables.Add("today", DateTime.Today.ToPersianString(PersianDateTimeFormat.Date));
return StiMvcViewer.GetReportSnapshotResult(HttpContext, report);
}
همه خطوط، همان قبلی هاست که بررسی کردیم؛ بجز خط آخر که یک ActionResult اختصاصی است که در آن نحوه انتقال اطلاعات به گزارش ساز پیاده سازی شده است و تنها کاری که باید بکنیم این است که شیء گزارش ایجاد شده در بالا را به آن پاس دهیم.

اگر دوباره در ویو مربوطه، به سراغ helper برویم می‌بینیم که سه اکشن متد دیگر وجود دارند که در زیر، به ترتیب با نحوه کار آن‌ها و کد اکشن متد آن‌ها اشاره میکنیم:
Viewer Events : این اکشن متد که تنها یک خط ActionResult استاتیک را فراخوانی می‌کند، جهت مدیریت رویدادهای گزارش چون: زوم، صفحه بندی گزارش، خروجی‌ها و چاپ می‌باشد و وجود آن در گزارش از الزامات است.
 public virtual ActionResult ViewerEvent()
 {
            return StiMvcViewer.ViewerEventResult();
 }

PrintReport: برای مدیریت و ارسال گزارشات به دستگاه چاپ می‌باشد. این اطلاعات از طریق شی HttpContext به سمت اکشن متد ارسال شده و توسط PrintReportResult آن را دریافت می‌کند.
public virtual ActionResult PrintReport()
        {
            return StiMvcViewer.PrintReportResult(this.HttpContext);
        }

ExportReport: گزارش ساز استیمول به شما اجاز میدهد در فرمت‌های گوناگونی چون xlsx,docx,pptx,pdf,rtf و ... از گزارش خود خروجی بگیرید. اطلاعات گزارش از طریق شی HttpContext به سمت اکشن متد ارسال شده و توسط ExportReportResult  دریافت می‌شود. 
 public virtual ActionResult ExportReport()
        {
            return StiMvcViewer.ExportReportResult(this.HttpContext);
        }
حال اگر برنامه را اجرا کنید، باید گزارشی به شکل زیر نمایش داده شود و مقادیر در جای خود شکل گرفته باشند. ولی مشکلی  که ممکن است این گزارش داشته باشد این است که برای فارسی، حالت راست به چپ را ندارد.


 البته خوشبختانه این مشکل  در حالت پیش نمایش و چاپ و خروجی‌ها دیده نمی‌شود و فقط مختص نمایش روی فرم Html است. برای حل این مشکل ممکن است از گزینه یا پراپرتی RightToLeft، در بخش Appearance موجود در helper استفاده کنید که البته استفاده از آن مانند تصویر بالا، فقط محدود به container گزارش و نوار ابزار آن می‌شود. برای حل این مشکل کافی است کد css زیر را به صفحه گزارش اضافه کنید تا مشکل حل شود:
.stiMvcViewerReportPanel table{
    direction:ltr !important;
}
مجددا گزارش را ایجادکنید تا گزارش را به طور صحیحی مشاهده کنید:

حال حتما پیش خود میگویید که این روش برای اطلاعات ایستا و تمرینی مناسب است و من چگونه باید پارامترهای ارسالی به اکشن متد Report را به اکشن متد LoadReportSnapshot ارسال کنم. برای این منظور استفاده از SessionState‌ها زیاد توصیه شده‌است:
 public virtual ActionResult Report(int id)
        {
            TempData["id"]=id;
            return View();
        }

         public virtual ActionResult LoadReportSnapshot()
        {
            var driverId = (int)TempData ["id"];
              //.....
        }
  ولی این روش مشکلات زیادی را دارد. اول اینکه اگر کاربر چند گزارش جداگانه را پشت سر هم باز کند، به دلیل اینکه گزارش مدتی طول می‌کشد باز شود، همه گزارش‌ها آخرین گزارش درخواستی خواهند بود و دوم اینکه مقداری از حافظه سرور را هم بی جهت اشغال میکند. ولی برای کار با استیمول به هیچ یک از این کارها نیازی نیست، چون خود استیمول به طور خودکار پارامترهای ارسالی را انتقال می‌دهد. یعنی کد باید به شکل زیر نوشته شود:
public virtual ActionResult Report(int id)
        {
    
            return View();
        }

         public virtual ActionResult LoadReportSnapshot(int id)
        {
             //.....
        }
همین مقدار کد برای ارسال پارمترها کفایت میکند و مابقی کار را به stimul بسپارید.

نکته بسیار مهم: گزارش ساز استیمول متاسفانه شامل تنظیم پیش فرض نامناسبی است که عملیات کش را بر روی گزارش‌ها اعمال می‌کند. به عنوان مثال تصور کنید من صفحه گزارش شخصی به نام «وحید نصیری» را باز میکنم و در تب دیگر گزارش شخص دیگری با نام «علی یگانه مقدم» را باز میکنم. حال اگر کاربر به سراغ تب آقای نصیری برود و بخواهد چاپ یا خروجی درخواست کند، اشتباها با گزارش علی یگانه مقدم روبرو خواهد شد که این اتفاق به دلیل کش شدن رخ میدهد. برای غیر فعال کردن این قابلیت پیش فرض، کد زیر را در Helper اضافه کنید:
Server =
    {
        GlobalReportCache = false
    }
مطالب
React 16x - قسمت 6 - کامپوننت‌ها - بخش 3 - یک تمرین
در این قسمت می‌خواهیم دانسته‌های 5 قسمت قبل را در طی یک تمرین کنار هم قرار داده و مرور کنیم.


برپایی ساختار ابتدایی پروژه‌ی تمرین

ابتدا یک پروژه‌ی جدید React را ایجاد می‌کنیم:
> create-react-app sample-05
> cd sample-05
> npm start
سپس بسته‌های بوت استرپ و font-awesome را نیز در آن نصب می‌کنیم:
> npm install --save bootstrap
> npm install --save font-awesome

در ادامه نیاز است فایل‌های CSS این کتابخانه‌ها و قلم‌های وب را import کنیم. به همین جهت ابتدای فایل index.js را به نحو زیر ویرایش خواهیم کرد:
import "bootstrap/dist/css/bootstrap.css";
import "font-awesome/css/font-awesome.css";
در نهایت کار مدیریت این فایل‌ها و قرار دادن آن‌ها در بسته‌ی نهایی برنامه، توسط webpack به صورت خودکار انجام می‌شود.

همچنین به فایل index.css هم مراجعه کرده و یک padding را به بالای صفحه اضافه می‌کنیم؛ تا اطلاعات نمایش داده شده، با کمی فاصله از لبه‌ی مرورگر رندر شوند:
body {
  margin: 0;
  padding: 20px 0 0 0;
  font-family: sans-serif;
}

پس از نصب و import این کتابخانه‌های ثالث، به فایل App.js مراجعه کرده و کلاس container اصلی بوت استرپ را در آن تعریف می‌کنیم تا در برگیرنده‌ی محتوای برنامه شود:
  return (
    <main className="container">
      <h1>Hello world!</h1>
    </main>
  );
همانطور که در قسمت چهارم نیز بحث شد، برای ذکر classهای عناصر در React، از خاصیت className استفاده می‌شود.


معرفی سرویس‌های داده‌ی برنامه

کدهای نهایی این قسمت را از فایل پیوست شده‌ی در انتهای مطلب، می‌توانید دریافت کنید. در اینجا یک پوشه‌ی src\services تعریف شده‌است که داخل آن دو فایل fakeGenreService.js و fakeMovieService.js قرار دارند. این فایل‌ها، منبع داده‌ی درون حافظه‌ای مثال تمرین ما هستند.
سرویس fakeGenre چنین ساختاری را دارد و ژانرهای سینمایی، مانند اکشن، کمدی و غیره در آن لیست شده‌اند:
export const genres = [
  { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
  // ...
];
این سرویس دارای متد ()getGenres، برای بازگشت لیست کامل genres است. علت ذکر خاصیت id با یک _، روش نامگذاری خاصیت id در mongo-db است.

و سرویس fakeMovie که دارای ساختار کلی زیر است، لیست 9 فیلم سینمایی را به همراه دارد:
const movies = [
  {
    _id: "5b21ca3eeb7f6fbccd471815",
    title: "Terminator",
    genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
    numberInStock: 6,
    dailyRentalRate: 2.5,
    publishDate: "2018-01-03T19:04:28.809Z"
  },

  //...
];
به علاوه این سرویس دارای متدهای ()getMovies برای دریافت لیست فیلم‌ها، getMovie(id) برای بازگشت یک فیلم خاص، saveMovie(movie) برای افزودن یک فیلم جدید به لیست و deleteMovie(id) برای حذف یک فیلم از لیست درون حافظه‌ای سرویس جاری است.


ایجاد کامپوننت Movies برای نمایش لیست فیلم‌ها در برنامه

اکنون می‌خواهیم یک کامپوننت جدید را به نام Movies در فایل جدید src\components\movies.jsx ایجاد کنیم، تا لیست فیلم‌های سرویس fakeMovieService را نمایش دهد. برای اینکار مراحل زیر را طی خواهیم کرد:
- نمایش ساده‌ی لیست فیلم‌ها توسط یک جدول. برای دریافت لیست اشیاء موجود در fakeMovieService، از متد ()getMovies آن می‌توان استفاده کرد.
- اضافه کردن یک دکمه‌ی حذف، به هر ردیف، به نحوی که با کلیک بر روی آن، آن ردیف حذف شود.
- نمایش یک پیام بالای جدول که تعداد فیلم‌های موجود در سرویس درون حافظه‌ای را نمایش می‌دهد. همچنین پس از حذف تمام ردیف‌ها، باید پیام «فیلمی موجود نیست» را نمایش دهد.

خروجی نهایی مثال ما به صورت زیر است:


و اگر تمام آیتم‌های آن‌را حذف کنیم، چنین پیامی نمایش داده می‌شود:


پس از ایجاد فایل خالی جدید movies.jsx در پوشه‌ی جدید components، با استفاده از «simple react snippets» نصب شده‌ی در VSCode، یکبار imrc را تایپ کرده (مخفف import react component است) و سپس دکمه‌ی tab را فشار می‌دهیم، در آخر اینکار را برای cc نیز تکرار می‌کنیم (مخفف create class است) تا importها و سپس ساختار ابتدایی کامپوننت React ما تشکیل شوند. نام این کامپوننت را هم Movies که با حرف بزرگ شروع می‌شود، وارد می‌کنیم.

اکنون مجددا به App.js مراجعه می‌کنیم و بجای Hello world ای که نمایش دادیم، کامپوننت Movies را اضافه می‌کنیم. برای این منظور ابتدا import آن‌را به ابتدای فایل اضافه می‌کنیم:
import Movies from "./components/movies";
سپس متد return آن‌را جهت درج المان کامپوننت Movies اصلاح خواهیم کرد:
return (
    <main className="container">
      <Movies />
    </main>
  );


دریافت لیست اشیاء فیلم‌ها از سرویس fakeMovieService

برای دریافت لیست اشیاء فیلم‌ها، ابتدا تعریف سرویس آن‌را به ابتدای کامپوننت Movies اضافه می‌کنیم:
 import { getMovies } from "../services/fakeMovieService";
در اینجا از {} استفاده شده، چون یک named export را import کرده‌ایم.

سپس خاصیت state را جهت تعریف خاصیت movies که با متد ()getMovies سرویس fakeMovieService مقدار دهی می‌شود، به نحو زیر تکمیل می‌کنیم:
 state = {
    movies: getMovies()
  };
البته این روش مقدار دهی اولیه‌ی خاصیت state، برای دریافت اطلاعات سرویس‌ها، هرچند در اینجا بدون مشکل کار می‌کند، اما بهتر است توسط component life cycle hooks مدیریت شود که در قسمت‌های بعدی بیشتر به جزئیات آن‌ها خواهیم پرداخت.


نمایش لیست فیلم‌ها، به همراه مدیریت حذف هر ردیف

در ادامه، کدهای کامل و تکمیل شده‌ی این کامپوننت را ملاحظه می‌کنید:
import React, { Component } from "react";

import { getMovies } from "../services/fakeMovieService";

class Movies extends Component {
  state = {
    movies: getMovies()
  };

  handleDelete = movie => {
    const movies = this.state.movies.filter(m => m._id !== movie._id);
    this.setState({ movies });
  };

  render() {
    const { length: count } = this.state.movies;

    if (count === 0) return <p>There are no movies in the database.</p>;

    return (
      <React.Fragment>
        <p>Showing {count} movies in the database.</p>
        <table className="table">
          <thead>
            <tr>
              <th>Title</th>
              <th>Genre</th>
              <th>Stock</th>
              <th>Rate</th>
              <th />
            </tr>
          </thead>
          <tbody>
            {this.state.movies.map(movie => (
              <tr key={movie._id}>
                <td>{movie.title}</td>
                <td>{movie.genre.name}</td>
                <td>{movie.numberInStock}</td>
                <td>{movie.dailyRentalRate}</td>
                <td>
                  <button
                    onClick={() => this.handleDelete(movie)}
                    className="btn btn-danger btn-sm"
                  >
                    Delete
                  </button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </React.Fragment>
    );
  }
}

export default Movies;
توضیحات:
همانطور که در ابتدای بحث نیز ذکر شد، هدف از این تمرین، مرور قسمت‌های قبل است و تمام نکات زیر را در قسمت‌های پیشین، با جزئیات بیشتری بررسی کرده‌ایم:

- ابتدا خاصیت state و سپس خاصیت movies شیء منتسب به آن، با لیست فیلم‌های موجود در سرویس مرتبط، مقدار دهی شده‌اند.
- سپس در ابتدای متد render، کار رندر شرطی انجام شده‌است. اگر تعداد فیلم‌های دریافتی صفر بود، پیام «فیلمی در بانک اطلاعاتی موجود نیست» نمایش داده می‌شود و در غیراینصورت، جدول اصلی بوت استرپی برنامه رندر خواهد شد.
در اینجا چون از خاصیت طول آرایه‌ی فیلم‌ها در چندین قسمت قرار است استفاده شود، آن‌را توسط Object Destructuring به یک متغیر نسبت داده‌ایم. همچنین توسط یک نام مستعار هم خاصیت length را با نام جدید count استفاده می‌کنیم.
- در ادامه بازگشت React.Fragment را مشاهده می‌کنید. علت اینجا است که نمی‌خواهیم div اضافه‌تری را در UI رندر کنیم. React.Fragment سبب می‌شود تا بتوانیم چندین فرزند را به المان جاری تبدیل شده‌ی به کدهای جاوا اسکریپتی اضافه کنیم، بدون اینکه خودش به المانی ترجمه شود.
- پس از return، یک () قابل مشاهده‌است. چون خروجی return ما چند سطری است، اگر در سطری که return قرار می‌گیرد، اطلاعاتی درج نشود، موتور جاوا اسکریپت آن‌را با یک سمی‌کالن خاتمه خواهد داد! و دیگر سطرهای بعدی دیده نمی‌شوند و پردازش نخواهند شد. به همین جهت از روش ذکر یک () پس از return در فایل‌های jsx زیاد استفاده می‌شود.
- در ابتدای return، همان خاصیت count را نمایش می‌دهیم.
- سپس کار رندر جدول اصلی برنامه که با کلاس‌های جداول بوت استرپ نیز مزین شده، انجام شده‌است. در React برای عدم تداخل ویژگی class با نام از پیش رزرو شده‌ی class، از خاصیت className برای ذکر کلاس‌های CSSای استفاده می‌شود.
- قسمت thead این جدول مشخص است و سرستو‌ن‌های جدول را مشخص می‌کند.
- پس از آن نیاز است ردیف‌های جدول را رندر کنیم. این‌کار را توسط متد Array.map، با نگاشت هر آیتم آرایه‌ی this.state.movies، به یک tr جدول انجام داده‌ایم.
- React برای اینکه بتواند DOM مجازی خودش را کنترل کند، نیاز دارد عناصر موجود در آن‌را به صورت منحصربفردی تشخص دهد. به همین جهت در اینجا ذکر key را بر روی المان tr که با movie._id مقدار دهی شده‌است، مشاهده می‌کنید.
- رندر مقادیر سلو‌ل‌های ردیف‌ها توسط درج {} و سپس ذکر مقداری از شیء movie دریافتی توسط متد Array.map انجام می‌شود.
- در اینجا ستون رندر دکمه‌ی Delete را نیز مشاهده می‌کنید. برای مدیریت this در آن و دسترسی به شیء movie جاری (ارسال پارامتر به رویداد گردان آن) و همچنین دسترسی به شیء this کلاس جاری برای کار با آرایه‌ی this.state.movies، از روش arrow functions برای تعریف رویدادگردان onClick استفاده کرده‌ایم.
- در متد handleDelete، یک آرایه‌ی جدید را که id ردیف‌های آن با id شیء ردیف انتخابی یکی نیست، بازگشت می‌دهیم. انتساب این آرایه‌ی جدید به آرایه‌ی this.state.movies، تغییری را در برنامه‌های React ایجاد نمی‌کند. در اینجا باید توسط متد this.setState که از کلاس پایه‌ی extends Component دریافت می‌شود، خاصیت movies را بازنویسی کرد تا React از تغییرات مطلع شده و DOM مجازی جدیدی را با مقایسه‌ی با نمونه جدید، محاسبه کرده و به DOM اصلی، جهت به روز رسانی UI اعمال کند.
- البته در اینجا this.setState({ movies }) را بجای this.setState({ movies: movies }) مشاهده می‌کنید. علت اینجا است که اگر عبارات key و value یکی باشند، می‌توان تنها همان عبارت key را جهت حذف تکرار واژه‌ها، ذکر کرد.



کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: sample-05.zip
نظرات مطالب
مقایسه رکوردهای دو جدول
جالب بود ولی این ها فقط برای SQL Server نیستند. بلکه دستورات کلی SQL هستند!
مطالب
آشنایی با FileTable در SQL Server 2012 بخش 1
پیش از آشنایی با FileTable نیاز است که پیشینه‌ای از شیوه‌های ذخیره‌سازی فایل و یا بهتر بگویم BLOB در SQL Server را داشته باشیم. نخستین شیوه‌ی نگه‌داری فایل استفاده از Image است که در SQL Server 2000 کاربرد داشت و هم‌اکنون استفاده از آن به دلیل کاهش بسیار کارآیی منسوخ‌شده است. به دلایل مشکلات بسیار فراوان Image هم‌زمان بسیاری از طراحان پایگاه داده‌ها، جهت کاهش حجم جدول‌ها و پیروی آن حجم پایگاه داده‌ها، فایل را در سیستم‌فایل نگه‌داری می‌کردند و تنها مسیر آن را در فیلدی از نوع کاراکتری در پایگاه‌داده‌ها ذخیره می‌کردند. این روش هرچند از حجم پایگاه داده‌ها می‌کاست ولی به دلیل عدم دخالت SQL Server در مدیریت فایل‌ها مشکلات دیگری را به وجود آورد.
از SQL Server 2005 نوع داده‌ی varbinary(max) معرفی شد که برخی از چالش‌های به‌کاربری Image را کاست و درباره‌ی بسیاری از موارد مانند ذخیره‌ی عکس پرسنلی هنوز هم کاربرد دارد؛ ولی توجه داشته باشید که استفاده از این فیلد فقط برای فایل‌های کم‌تر از 256 کیلوبایت سفارش شده است و برای بالاتر از آن، کارآیی کاهش فراوانی خواهد یافت.
در  SQL Server 2008 نوع داده‌ی جدیدی به نام FileStream به وجود آمد به این شکل که یک FileGroup از نوع  Data FileStream به پایگاه‌داده افزوده می‌شود و در واقع با یک پوشه در سیستم فایل در پیوند است. از این پس هنگام ساخت یک جدول به جای استفاده از نوع داده‌ی varbinary از نوع FileStream استفاده می‌کنیم با مد نظر داشتن این نکته که حتماً باید یک فیلد از نوع Uniqueidentifier هم در آن جدول تعریف شده باشد. شیوه‌ی کار نیز به این صورت خواهد بود که خود رکورد در جدول ذخیره می‌شود و فقط محتوای فایل در آن مسیری از NTFS ذخیره می‌شود. برخلاف روش درج مسیر فایل در جدول که پس از حذف رکورد، فایل هم‌چنان در سیستم فایل می‌ماند؛ این بار با حذف رکورد فایل مربوطه نیز حذف خواهد شد. افزون بر این مدیریت پشتیبانی از فایل‌ها نیز برعهده‌ی پایگاه داده‌ها خواهد بود. اندازه‌ی فایل‌ها در FileStream محدودیت‌های پیشین را نخواهد داشت و شما به اندازه‌ی حجم درایو هارددیسک می‌توانید فایل در آن ذخیره کنید. نکته‌ی دیگر درباره‌ی فایل‌های با حجم سنگین که می‌توانید Stream مربوط به یک فایل را به صورت بخش‌بخش در سمت مشتری بارگذاری کنید و به او نشان دهید. در FileStream امنیت و تراکنش فایل‌ها برعهده‌ی SQL Server است و از این دیدگاه بسیار ساده‌تر و کارآتر از FileSystem است. (برای آشنایی بیشتر با FileStream، این نوشتار از مهندس وحید نصیری را مطالعه کنید.)
گونه‌ی FileTable از ویژگی‌های نوین SQL Server 2012 است که تکمیل‌کننده‌ی FileStream است. FileTable آمیزشی از FileStream با hierarchyid و سیستم فایل ویندوز برای ارائه‌ی توانایی‌های نوین مدیریت BLOB در  SQL Server است. FileTable همان‌گونه که از دو واژه‌ی تشکیل‌دهنده‌اش پیداست؛ هم‌زمان یک جدول و یک سیستم فایل معمولی است.
FileTable به هر روی یک جدول از پایگاه‌داده‌های SQL Server است با یک تفاوت که ساختار آن از پیش تعریف‌شده است. ستون‌های FileTable و نوع داده‌ی آن از پیش توسط SQL Server  مشخص شده است. ستون‌های تشکیل‌دهنده‌ی FileTable دربرگیرنده‌ی جدول زیر است:

هر ردیف از FileTable نماینده‌ی یک فایل یا پوشه در File System است. ستون path_locator که از نوع hierarchyid است نشان‌دهنده‌ی مسیر یک فایل یا پوشه است. hierarchyid که از SQL Server 2008 معرفی شده است؛ بهترین نوع داده برای نگه‌داری ارتباط ساختار سلسله‌مراتبی مانند چارت سازمانی، درخت تجهیزات یک کارخانه و یا در همین نمونه درخت فایل‌ها و پوشه‌ها است. پس می‌توانیم از همه‌ی امکانات hierarchyid در FileTable نیز برخوردار شویم. این‌که این فایل به ترتیب در چه پوشه‌هایی قرار گرفته است یا این‌که این پوشه شامل چه فایل‌ها یا پوشه‌هایی خواهد بود. این‌که پوشه‌های هم‌فرزند پوشه‌ی جاری کدام است و یا یا توابع مربوط به جابه‌جایی فایل‌ها و پوشه‌ها.

دنباله دارد...

نظرات مطالب
LocalDB FAQ
اتصال به LocalDB توسط Rider

در تنظیمات Data Source جهت اتصال به LocalDB در Rider این مراحل باید طی شوند:
- پیش از هر کاری دو دستور زیر را اجرا کنید:
C:\>"C:\Program Files\Microsoft SQL Server\140\Tools\Binn\SqlLocalDB.exe" i
MSSQLLocalDB
ProjectsV13
v12.0

C:\>"C:\Program Files\Microsoft SQL Server\140\Tools\Binn\SqlLocalDB.exe" s MSSQLLocalDB
LocalDB instance "MSSQLLocalDB" started.
دستور اول وهله‌های نصب شده را نمایش می‌دهد و دستور دوم اولین وهله را آغاز می‌کند.
خود Rider آغازگر این وهله‌ها نخواهد بود. به همین جهت نیاز است دستی آغاز شوند.


- سپس در صفحه تنظیمات Data Source، نوع Driver را بر روی SQL Server (jTds) قرار دهید.
- پایین صفحه، لینک download missing driver files ظاهر می‌شود. بر روی آن کلیک کنید تا به سرعت کار نصب و راه اندازی درایور کم حجم آن انجام شود.
- اکنون می‌توانید در قسمت URL، گزینه‌ی LocalDB و سپس وهله‌ی MSSQLLocalDB را از لیست Instance انتخاب کنید.
- در آخر بر روی دکمه‌ی Test Connection کلیک کنید. اگر درایور را نصب نکرده باشید، این دکمه قابل انتخاب نخواهد بود.
مطالب
لینک‌های هفته اول آذر

وبلاگ‌ها و سایت‌های ایرانی


Visual Studio


ASP. Net


طراحی وب


اس‌کیوال سرور


به روز رسانی‌ها


سی‌شارپ


عمومی دات نت


PHP



متفرقه



مطالب
React 16x - قسمت 1 - معرفی و شروع به کار
React یک کتابخانه‌ی جاوا اسکریپتی، برای ساخت رابط‌های کاربری سریع و تعاملی است. توسعه‌ی آن از سال 2011 در فیسبوک شروع شد و در حال حاضر محبوب‌ترین کتابخانه‌ی جاوا اسکریپتی در این رده‌است:


به همین جهت اگر می‌خواهید رزومه‌ی غنی‌تری را ارائه دهید، فراگیری React می‌تواند موقعیت‌های شغلی بیشتری را نصیب شما کند.


ساختار کلی یک برنامه‌ی React

کامپوننت‌ها (جزئی از یک رابط کاربری) قلب هر برنامه‌ی React ای را تشکیل می‌دهند. برای ساخت یک برنامه‌ی React، تعدادی کامپوننت مستقل را تهیه و با هم ترکیب می‌کنیم تا به رابط کاربری نهایی برسیم.
هر برنامه‌ی React، حداقل از یک کامپوننت تشکیل می‌شود که به آن Root component هم می‌گویند. این کامپوننت بیانگر کل برنامه‌است و دربرگیرنده‌ی مابقی Child components برنامه است. بنابراین ساختار هر برنامه‌ی React، شبیه به درختی از کامپوننت‌ها است. اگر با Angular 2 به بعد کار کرده باشید، این مفهوم برای شما آشنا است.
یک مثال: فرض کنید می‌خواهیم UI برنامه‌ای را به مانند رابط کاربری Twitter، ایجاد کنیم. هر قسمت یک صفحه‌ی توئیتر، به کامپوننت‌هایی شکسته می‌شود؛ مانند منوی راهبری، نمایش پروفایل شخص، نمایش لیست آخرین اخبار مورد علاقه‌ی شخص و نمایش فید. اگر بخواهیم این ساختار را توسط یک برنامه‌ی React شبیه سازی کنیم، در بالاترین سطح، کامپوننت root را خواهیم داشت که کار ترکیب و نمایش سایر کامپوننت‌های برنامه مانند nav bar ، trends ، profile و feed را انجام می‌دهد. اکنون در این ساختار ایجاد شده، برای مثال کامپوننت feed نیز می‌تواند از چندین کامپوننت مجزا تشکیل شود؛ مانند کامپوننت‌های tweet و like.
بنابراین هر کامپوننت، قسمتی از UI را تشکیل می‌دهد. هر کدام از آن‌ها به صورت مجزای از دیگری ساخته شده و سپس در کنار هم قرار می‌گیرند تا UI نهایی را شکل دهند:



هر کامپوننت در React به صورت یک کلاس ES6، با ساختاری که دارای یک شیء state و متد render است، تشکیل می‌شود:
class Tweet {
 state = {};
 
 render() {
 } 
}
state در اینجا همان اطلاعاتی است که قرار است در زمان نمایش این کامپوننت، رندر شود. کار متد render نیز همانطور که از نام آن نیز مشخص است، بیان نحوه‌ی تشکیل و رندر UI است. خروجی این متد، یک React Element است که در حقیقت یک شیء جاوا اسکریپتی خالص است و در نهایت به المان‌های DOM، نگاشت می‌شود. یک React Element، یک DOM Element واقعی نیست؛ بلکه تنها یک شیء جاوا اسکریپتی بیانگر DOM Element، در حافظه‌است. بنابراین یک برنامه‌ی React تشکیل شده‌است از لیستی از React Elementها در حافظه که به آن Virtual DOM هم گفته می‌شود.
مزیت کارکردن با Virtual DOM، سادگی ایجاد، تغییر و به روز رسانی آن در مقایسه با DOM واقعی است که در نهایت کار رندر عناصر UI را در مرورگر انجام می‌دهد. زمانیکه در state کامپوننتی تغییری رخ می‌دهد، یک React Element جدید تولید می‌شود. سپس React این شیء جدید را با نمونه‌ی قبلی آن مقایسه کرده و تغییرات رخ‌داده را محاسبه می‌کند. در آخر این تغییرات را به DOM واقعی اعمال می‌کند تا با Virtual DOM موجود هماهنگ شود.
بنابراین در حین کار با React، دیگر همانند کار با جاوا اسکریپت خالص و یا jQuery، مستقیما عناصر UI و DOM واقعی را تغییر نمی‌دهیم. در اینجا فقط state یک کامپوننت را تغییر می‌دهیم و سپس React، کار ایجاد شیء UI درون حافظه‌ای متناظر با آن و سپس اعمال آن‌را به UI نهایی قابل مشاهده‌ی در مرورگر، انجام می‌دهد. به همین جهت به این کتابخانه React می‌گویند! چون به تغییرات state کامپوننت‌ها واکنش نشان می‌دهد و سپس DOM واقعی را به روز می‌کند.


Angular یا React؟!

هر دوی React و Angular از لحاظ طراحی کامپوننت‌ها بسیار شبیه به هم هستند؛ اما Angular یک فریم‌ورک است و React تنها یک کتابخانه. تنها کاری را که React انجام می‌دهد، رندر View است و هماهنگ نگه داشتن آن با state کامپوننت‌ها. این تمام کاری است که React انجام می‌دهد؛ نه بیشتر و نه کمتر! بنابراین یادگیری React، بسیار سریع‌تر و ساده‌تر از Angular است. بدیهی است یک برنامه‌ی تک صفحه‌ای وب، از اجزای دیگری مانند مسیریابی و یا کار با سرویس‌های HTTP نیز تشکیل می‌شود. در React شما مختار هستید که کتابخانه‌های جانبی فراهم شده‌ی برای آن‌را خودتان انتخاب کرده و استفاده کنید؛ برخلاف روشی که در Angular مرسوم است و به صورت مشخص و ثابتی به همراه این فریم‌ورک ارائه می‌شوند.


برپایی محیط توسعه‌ی React

اولین برنامه‌ای را که برای کار با React باید نصب کنید، node.js است. البته ما در این سری قرار نیست با node.js کار کنیم؛ اما از یکی از اجزای آن به نام node package manager یا npm، برای نصب کتابخانه‌ی جاوا اسکریپتی ثالث، زیاد استفاده خواهیم کرد. پس از نصب آن، به خط فرمان مراجعه کرد و دستور زیر را صادر کنید:
> npm install -g npm@latest
این دستور npm قدیمی موجود بر روی سیستم را به روز رسانی می‌کند (اگر پیشتر یک node.js قدیمی را نصب و اکنون آن‌را به روز رسانی کرده‌اید).

اگر هم خیلی پیشترها node.js را نصب کرده‌اید (برای مثال چند سال قبل!)، نصب نگارش جدید آن احتمالا کار نخواهد کرد. حتی عزل و نصب مجدد آن نیز کارساز نیست. در این حالت باید پس از عزل آن، پوشه‌های قدیمی آن‌را یکی یکی یافته و دستی حذف کنید . سپس مجددا آن‌را نصب کنید.

در ادامه در خط فرمان و توسط npm، قالب create-react-app را نصب خواهیم کرد:
> npm i -g create-react-app
در اینجا سوئیچ i به معنای install است و g یعنی نصب global و سراسری بسته‌ی create-react-app. نصب سراسری یک بسته یعنی در هر پوشه‌ای می‌توان به امکانات آن دسترسی یافت و از آن استفاده کرد. اگر از سوئیچ g استفاده نمی‌شد، این بسته تنها در پوشه‌ی جاری و با سطح دید مختص به آن، نصب و قابل استفاده می‌شد.

ابزار دیگری که در این سری از آن استفاده خواهیم کرد، ادیتور بسیار معروف و محبوب VSCode است. پس از دریافت و نصب آن، چند افزونه‌ی زیر را نیز به آن اضافه خواهیم کرد:
برای نصب آن‌ها، پنل extensions را در VSCode، از نوار ابزار کنار صفحه‌ی آن، انتخاب کرده و نام‌های فوق را در آن جستجو و سپس نصب کنید.

و یا می‌توانید این فایل را اجرا کرده و تعدادی از افزونه‌های مفید VSCode را یکجا نصب کنید: install-addons.zip

همچنین قابلیت فرمت‌کردن پس از Save را نیز در VSCode فعال کنید تا پس از هربار Save، اعمال این افزونه‌ها به صورت خودکار صورت گیرد. برای این منظور گزینه‌ی file->preferences->settings را در VSCode انتخاب کرده و سپس save را جستجو کرده و Format On Save را انتخاب کنید:


علاوه بر این‌ها، جهت کار بهتر با VSCode، بهتر است بررسی کننده‌های کدهای جاوا اسکریپتی (static code analyzers) را نیز با اجرای دستور زیر نصب کنید:
> npm i -g typescript eslint tslint eslint-plugin-react-hooks

پس از این تغییرات، نیاز است یکبار VSCode را بسته و مجددا باز کنید. سپس مجددا گزینه‌ی file->preferences->settings را در VSCode انتخاب کرده و ابتدا eslint را در اینجا جستجو کنید. در صفحه‌ی نمایش تنظیمات آن، گزینه‌ی Auto fix on save آن‌را انتخاب نمائید. در آخر در همین قسمت settings، عبارت prettier را انتخاب کنید. در اینجا اگر گزینه‌ی قدیمی یکپارچگی با eslint آن هنوز وجود دارد، آن‌را از حالت انتخاب شده خارج کنید (به صورت قرمز و deprecated نمایش داده می‌شود) تا افزونه‌ی prettier بدون مشکل و خطا کار کند (disable Prettier ESLint integration).


ایجاد قالب اولین برنامه‌ی React

در ادامه برای ایجاد اولین برنامه‌ی React، از بسته‌ی create-react-app که پیشتر آن‌را نصب کردیم، استفاده می‌کنیم. برای این منظور در خط فرمان دستور زیر را صادر کنید:
> create-react-app sample-01
در اینجا sample-01 یک نام دلخواه است و در حین اجرای این دستور باید به اینترنت متصل باشید تا وابستگی‌های مرتبط با پروژه را نیز دریافت کند. برای بار اول، اجرای آن ممکن است کمی طول بکشد. اما از دفعات آتی، چون بسته‌های مرتبط را در npm-cache سیستم نیز ذخیره می‌کند، اجرای آن بسیار سریع خواهد بود.
این قالب نه تنها React را نصب می‌کند، بلکه یک development server را برای اجرا و مشاهده‌ی سریع برنامه، webpack را برای یکی کردن فایل‌ها (bundling & minification)، Babel را برای کامپایل کدهای فایل‌های JSX و ... نیز نصب می‌کند. بنابراین به این ترتیب، یک پروژه‌ی تنظیم شده و آماده‌ی استفاده و توسعه را شاهد خواهیم بود که نیازی به تنظیمات اولیه‌ی آن نیست.
پس ایجاد برنامه، وارد پوشه‌ی sample-01 شده و دستور npm start را صادر کنید:
> cd sample-01
> npm start
به این ترتیب برنامه بر روی پورت 3000، قابل دسترسی و مشاهده می‌شود:


development server آن، تغییرات فایل‌های برنامه را تحت نظر قرار می‌دهد و با هر تغییری، به صورت خودکار برنامه را در مرورگر بارگذاری مجدد خواهد کرد.


بررسی ساختار اولین پروژه‌ی React ایجاد شده

ساختار پوشه‌ها و فایل‌های مثال اولیه‌ی ایجاد شده توسط قالب create-react-app به صورت زیر است:


البته شما در این تصویر پوشه‌ی node_modules را که در کنار این پوشه‌ها قرار دارد، مشاهده نمی‌کنید. وجود یک چنین پوشه‌ی سنگینی با هزاران فایل داخل آن، کار نمایشی IDEها را با مشکل مواجه می‌کند (مصرف حافظه‌ی بالا، به همراه کند شدن شدید آن). اگر نمی‌خواهید این پوشه نمایش داده شود، در مسیر file->preferences->settings، عبارت npm را جستجو کرده و سپس در قسمت npm: exclude آن، بر روی لینک edit in settings.json کلیک کنید:


 و سپس در فایل باز شده، یک چنین تنظیمی را می‌توانید اضافه و یا ویرایش و تکمیل کنید:
  "files.exclude": {
    "**/.git": true,
    "**/.svn": true,
    "**/.hg": true,
    "**/CVS": true,
    "**/.DS_Store": true,
    "**/node_modules": true,
    "**/wwwroot": true,
    "**/bower_components": true,
    "**/**/bin": true,
    "**/**/obj": true,
    "**/packages": true
  },

در ادامه پوشه‌ی public این پروژه را مشاهده می‌کنید. تمام فایل‌هایی که قرار است به صورت عمومی توسط برنامه ارائه شوند، مانند favicon.ico و غیره، در این پوشه قرار می‌گیرند.
در این پوشه بر روی فایل index.html آن کلیک کنید تا بتوان محتوای آن‌را بهتر بررسی کرد. برای مثال در ابتدای آن، درج تعدادی متادیتا را که یکی از آن‌ها ذکر manifest.json است، مشاهده می‌کنید. کار فایل manifest.json، ارائه‌ی یک سری متادیتای خاص مخصوص دستگاه‌های موبایل است که در آن‌ها بجای favicon.ico، می‌توان از تصاویر و یا آیکن‌های بزرگتری مانند فایل‌های png موجود در پوشه‌ی public، استفاده کرد. در ادامه‌ی این فایل، به تنظیم زیر می‌رسیم:
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
div با id مساوی root، محل ارائه‌ی کل برنامه‌ی React ما است.

در پوشه‌ی src و فایل App.js آن، شاهد یک کامپوننت ابتدایی هستید که کار رندر صفحه‌ی مشکی پیش‌فرض این قالب را انجام می‌دهد. در این فایل، شاهد بازگشت یک چنین تگ‌هایی هستیم:
  return (
    <div className="App">
      <header className="App-header">
       ... 
      </header>
    </div>
  );
احتمالا تابحال چنین return ای را در برنامه‌های جاوا اسکریپتی مشاهده نکرده‌اید؛ چون درج آن‌ها در فایل‌های js به این نحو، غیرمجاز است. این تگ‌ها نه رشته‌ای هستند و نه HTML خالص. به آن jsx گفته می‌شود که مخفف JavaScript XML می‌باشد. کار آن ارائه‌ی ساختار UI ای است که قرار است رندر شود. یک چنین کدی برای اینکه قابل تفسیر و اجرا باشد، از درون کامپایلر ویژه‌ای به نام Babel عبور می‌کند و تبدیل به کدهای جاوا اسکریپتی خالصی می‌شود که برای مرورگرها قابل درک و اجرا است.
برای درک بهتر آن به آدرس https://babeljs.io/repl مراجعه کنید. سپس در سمت چپ صفحه، یک قطعه کد jsx را به یک ثابت انتساب دهید:
const element = <h1>Hello World!</h1>;


همانطور که مشاهده می‌کنید، این قطعه کد jsx (که یک رشته‌ی معمولی نیست)، توسط Babel به یک قطعه کد کاملا جاوا اسکریپتی قابل درک برای مرورگر تبدیل شده‌است:
"use strict";

var element = React.createElement("h1", null, "Hello World!");

بدیهی است نوشتن کدهای jsx، ساده‌تر از نوشتن قطعه کد فوق است و درک آن نیز به علت شباهت آن به HTML، آسان‌تر است. به همین جهت در کدهای React، ما از jsx استفاده می‌کنیم و تفسیر آن‌را به Babel واگذار خواهیم کرد.

در پوشه‌ی src، فایل مهم دیگری که وجود دارد، index.js است. این فایل نقطه‌ی آغازین برنامه را مشخص می‌کند. در قسمت‌های بعدی، محتویات این فایل را بیشتر بررسی خواهیم کرد.
در اینجا فایل serviceWorker.js را نیز مشاهده می‌کنید. این فایل به صورت خودکار توسط قالب create-react-app ایجاد شده‌است و کار آن کمک به ارائه‌ی محلی برنامه، توسط development server آن است. بنابراین ما کاری با این فایل نخواهیم داشت.


نوشتن اولین برنامه‌ی React

به پوشه‌ی src ایجاد شده مراجعه کرده و تمام فایل‌های موجود و پیش‌فرض آن‌را حذف کنید. در ادامه خودمان آن‌ها را از صفر ایجاد خواهیم کرد. برای این منظور فایل جدید و خالی src\index.js را ایجاد می‌کنیم. در ابتدای کار نیاز است تعدادی ماژول React را import کنیم.
import React from "react";

const element = <h1>Hello World!</h1>;
console.log(element);
در اینجا شیء React از ماژول react دریافت شده و سپس یک ثابت را با یک عبارت jsx مقدار دهی کرده‌ایم. چون از jsx استفاده می‌کنیم، ذکر import ابتدای فایل الزامی است؛ از این جهت که Babel به کمک آن است که می‌تواند معادل React.createElement را تولید کند.
اگر هنوز برنامه توسط دستور npm start در حال اجرا است، هر بار که فایل index.js را ذخیره می‌کنیم، خروجی نهایی را در مرورگر نمایش می‌دهد (اگر هم آن‌را بسته‌اید، یکبار از طریق خط فرمان، دستور npm start را در ریشه‌ی پروژه، صادر کنید). به این قابلیت hot module reloading هم گفته می‌شود.
در این حالت اگر به مرورگر مراجعه کنید، یک صفحه‌ی سفید را مشاهده خواهید کرد. اکنون دکمه‌ی F12 را فشرده (و یا ctrl+shift+i) و developer console مرورگر را باز کنید.


شیءای را که در اینجا مشاهده می‌کنید، همان حاصل console.log کدهای فوق است؛ به عبارتی Babel، عبارت jsx ما را تبدیل به یک شیء جاوا اسکریپتی قابل فهم برای مرورگر کرده‌است که از دیدگاه React، جزئی از همان Virtual DOM ای است که پیشتر معرفی شد (نمایش درون حافظه‌ای DOM مختص React، جهت محاسبه‌ی تغییرات، با تغییر state هر کامپوننت و سپس اعمال آن‌ها به DOM اصلی در مرورگر).
اکنون می‌خواهیم این المان را در DOM اصلی، رندر کرده و نمایش دهیم:
import React from "react";
import ReactDOM from "react-dom";

const element = <h1>Hello World!</h1>;
console.log(element);

ReactDOM.render(element, document.getElementById("root"));
برای این منظور نیاز است از متد ReactDOM.render استفاده کرد. این شیء در ماژول react-dom قرار دارد؛ به همین جهت در ابتدای فایل import شده‌است. سپس در متد render آن، ابتدا المانی که قرار است رندر شود ذکر خواهد شد و سپس محل درج آن‌را مشخص می‌کنیم که دقیقا به همان div با id مساوی root در فایل public\index.html اشاره می‌کند.
اکنون پس از ذخیره سازی فایل index.js، اگر به مرورگر مراجعه کنید، عبارت Hello World! را مشاهده خواهید کرد:


همانطور که در این تصویر نیز مشخص است، المان h1 ما را داخل div ای با id مساوی root، درج کرده‌است.

هدف از این مثال ساده، نمایش نحوه‌ی کارکرد React، در پشت صحنه بود. در یک برنامه‌ی واقعی، بجای رندر یک المان ساده در DOM، کار رندر App component را انجام خواهیم داد. کامپوننت App، کامپوننت ریشه‌ای برنامه بوده و می‌تواند شامل درختی از کامپوننت‌ها که UI نهایی را تشکیل می‌دهند، شود.


نگاهی به تنظیمات پروژه‌ی ایجاد شده

اگر فایل package.json پروژه را باز کنید، یک چنین بسته‌هایی در آن درج شده‌است:
{
  "name": "sample-01",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.11.0",
    "react-dom": "^16.11.0",
    "react-scripts": "3.2.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
در اینجا صرفا سه بسته‌ی react، react-dom و react-scripts را در قسمت dependencies مشاهده می‌کنید که کل Importهای ما را تشکیل می‌دهند.
بسته‌ی react-scripts است که کار مدیریت چهار جزء قسمت scripts این فایل را انجام می‌دهد. برای نمونه دستور npm start ای که در اینجا تعریف شده، سبب اجرای react-scripts start می‌شود. در ادامه اگر دستور npm run build را اجرا کنیم، یک بسته‌ی نهایی بهینه سازی شده را تولید می‌کند.
آخرین دستور آن eject است. اگر دستور npm run eject را اجرا کنید، امکان سفارشی سازی پشت صحنه‌ی create-react-app را خواهید داشت؛ اما در نهایت به یک فایل package.json بسیار شلوغ خواهیم رسید (اینبار ارجاعات به Babel، Webpack و تمام ابزارهای دیگر نیز ظاهر می‌شوند). همچنین این عملیات نیز یک طرفه‌است. یعنی از این پس قرار است کنترل تمام این پشت صحنه، در اختیار ما باشد و به روز رسانی‌های بعدی create-react-app را با مشکل مواجه می‌کند. این گزینه صرفا مختص توسعه دهندگان پیشرفته‌ی React است.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: sample-01.zip

در قسمت بعد، پیشنیازهای جاوا اسکریپتی شروع به کار با React را بررسی می‌کنیم.