نظرات مطالب
نگارش نهایی MBUnit 3 ارائه شد
سلام باز خسته نباشی، مرجعی برای کسی که میخواد تازه شروع کنه حالا چه فارسی یا انگلیسی میشه معرفی کنید.
نظرات مطالب
ایجاد سرویس چندلایه‎ی WCF با Entity Framework در قالب پروژه - 9
سلام
فکر می‌کنم ایراد از تنظیمات IIS ویندوز باشه و ربطی به برنامه نویسی نداره
اول که IIS تنظیم می‌کردم این Error میداد

 HTTP Error 404.3 - Not Found The page you are requesting cannot be served because of the
extension configuration. If the page is a script, add a handler. If the file should be downloaded, 
add a MIME map
 که کارهایی که در وبلاگ زیر گفته شده انجام دادم
http://blogs.msdn.com/b/ericwhite/archive/2010/05/11/getting-started-building-a-wcf-web-service.aspx
الان پیغام زیر رو میده
 Server Error in '/MyNewService' Application.
Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
ممنون میشم اگه بتونی مشکل منو حل کنی
با تشکر
مطالب
React 16x - قسمت 5 - کامپوننت‌ها - بخش 2 - نمایش لیست‌ها و مدیریت رویدادها و حالات
در قسمت قبل، اولین کامپوننت React خود را ایجاد کردیم و سپس جزئیات بیشتری از عبارات JSX را مانند نحوه‌ی تعریف المان‌های مختلف و تنظیم مقادیر ویژگی‌های آن‌را بررسی کردیم. در ادامه‌ی همان مثال، در این قسمت، نحوه‌ی نمایش لیست‌ها و تعریف و مدیریت رویدادها را در کامپوننت‌های React، بررسی می‌کنیم.


نحوه‌ی رندر لیستی از اشیاء در کامپوننت‌های React

فرض کنید می‌خواهیم لیستی از تگ‌ها را رندر کنیم. برای این منظور ابتدا داده‌های مرتبط را به خاصیت state کامپوننت، اضافه می‌کنیم:
class Counter extends Component {
  state = {
    count: 0,
    tags: ["tag 1", "tag 2", "tag 3"]
  };
اکنون می‌خواهیم tags را توسط المان‌های ul و ui رندر کنیم. اگر با Angular کار کرده باشید، به همراه یک دایرکتیو ngFor است که توسط آن می‌توان یک حلقه را در قالب جاری، پیاده سازی و رندر کرد. اما در React و عبارات JSX، چیزی به نام مفهوم حلقه‌ها وجود خارجی ندارد؛ چون JSX یک templating engine نیست. فقط بیان ساده‌ی المان‌هایی است که قرار است توسط کامپایلر Babel به کدهای جاوا اسکریپتی ترجمه شوند. بنابراین اکنون این سؤال وجود دارد که چگونه می‌توان لیستی از عناصر را در اینجا رندر کرد؟
در مطلب «React 16x - قسمت 3 - بررسی پیشنیازهای جاوا اسکریپتی - بخش 2» در مورد متد Array.map بحث شد. در اینجا می‌توان توسط متد map، هر المان آرایه‌ی تگ‌ها را به یک المان React تبدیل و سپس رندر کرد:
class Counter extends Component {
  state = {
    count: 0,
    tags: ["tag 1", "tag 2", "tag 3"]
  };

  render() {
    return (
      <div>
        <span className={this.getBadgeClasses()}>{this.formatCount()}</span>
        <button className="btn btn-secondary btn-sm">Increment</button>
        <ul>
          {this.state.tags.map(tag => (
            <li>{tag}</li>
          ))}
        </ul>
      </div>
    );
  }
در این مثال، داخل المان ul، با یک {} شروع می‌کنیم تا بتوان به صورت پویا به مقدار آرایه‌ی this.state.tags دسترسی پیدا کرد. سپس متد map را بر روی این آرایه فراخوانی می‌کنیم. متد map، هر عضو آرایه‌ی tags را به callback function آن ارسال کرده و خروجی آن‌را به صورت یک عبارت JSX که در نهایت به یک المان جاوا اسکریپتی خالص ترجمه خواهد شد، تبدیل می‌کند. این فرآیند سبب رندر لیست tags می‌شود:


هرچند اکنون لیستی از تگ‌ها در مرورگر رندر شده‌اند، اما در کنسول توسعه دهندگان مرورگر، یک اخطار نیز درج شده‌است. علت اینجا است که React نیاز دارد تا بتواند هر آیتم رندر شده را به صورت منحصربفردی شناسایی کند. هدف این است که بتواند در صورت تغییر state هر المان در DOM مجازی خودش، خیلی سریع تشخیص دهد که چه چیزی تغییر کرده و فقط کدام قسمت خاص را باید در DOM اصلی، درج و به روز رسانی کند. برای رفع این مشکل، ویژگی key را به هر المان li در کدهای فوق اضافه می‌کنیم:
<li key={tag}>{tag}</li>
البته در مثال ما تگ‌ها منحصربفرد هستند؛ بنابراین استفاده‌ی از آن‌ها به عنوان key، مشکلی را ایجاد نمی‌کند. در یک برنامه‌ی مفصل‌تر، تگ‌ها می‌توانند شیء بوده و هر شیء دارای خاصیت id باشد که در این حالت فرضی می‌توان از tag.id به عنوان key استفاده کرد. همچنین باید دانست که این key فقط نیاز است در لیست ul، منحصربفرد باشد و نیازی نیست تا در کل DOM منحصربفرد باشد.


رندر شرطی عناصر در کامپوننت‌های React

در اینجا می‌خواهیم اگر تگی وجود نداشت، پیام متناسبی ارائه شود؛ در غیراینصورت لیست تگ‌ها همانند قبل نمایش داده شود (رندر شرطی یا conditional rendering). برای انجام اینکار در React، برخلاف Angular، دارای دایرکتیوهای ساختاری if/else نیستیم؛ چون همانطور که عنوان شد، JSX یک templating engine نیست. به همین جهت برای رندر شرطی المان‌ها در React، باید از همان جاوا اسکریپت خالص کمک بگیریم:
  renderTags() {
    if (this.state.tags.length === 0) {
      return <p>There are no tags!</p>;
    }

    return (
      <ul>
        {this.state.tags.map(tag => (
          <li key={tag}>{tag}</li>
        ))}
      </ul>
    );
  }
یک روش حل این مساله، نوشتن متدی است که به همراه یک if/else است. در اینجا اگر آرایه‌ی تگ‌ها، دارای عنصری نبود، یک پاراگراف متناظر نمایش داده می‌شود، در غیراینصورت همان قسمت رندر لیست تگ‌ها را که توسعه دادیم، بازگشت می‌دهیم. بنابراین این متد، دو خروجی JSX را بسته به شرایط مختلف می‌تواند داشته باشد. سپس از این متد به صورت {()this.renderTags} در متد render اصلی استفاده می‌کنیم:
  render() {
    return (
      <div>
        <span className={this.getBadgeClasses()}>{this.formatCount()}</span>
        <button className="btn btn-secondary btn-sm">Increment</button>
        {this.renderTags()}
      </div>
    );
  }
برای آزمایش آن هم یکبار آرایه‌ی tags را به نحو زیر خالی کنید:
  state = {
    count: 0,
    tags: []
  };

روش دوم حل این نوع مساله‌ها، استفاده از روش زیر است؛ در این حالت خاص، فقط یک if را داریم، بدون وجود قسمت else:
{this.state.tags.length === 0 && "Please create a new tag!"}
ابتدا شرط مدنظر نوشته می‌شود، سپس پیامی را که باید در این حالت ارائه شود، پس از && می‌نویسیم. در مثال فوق اگر آرایه‌ی tags خالی باشد، پیامی نمایش داده می‌شود.
اما این روش چگونه کار می‌کند؟! در اینجا && را به دو مقدار مشخص اعمال کرده‌ایم. یکی حاصل یک مقایسه است و دیگری یک مقدار رشته‌ای مشخص. در جاوا اسکریپت برخلاف سایر زبان‌های برنامه نویسی، می‌توان && را بین دو مقدار غیر Boolean نیز اعمال کرد. در جاوا اسکریپت، یک رشته‌ی خالی به false تعبیر می‌شود و اگر تنها دارای یک حرف باشد، true درنظر گرفته می‌شود. برای نمونه در ترکیب 'true && 'Hi، هر دو قسمت به true تفسیر می‌شوند. در این حالت موتور جاوا اسکریپت، دومین عبارت (آخرین عبارت && شده) را بازگشت می‌دهد. همچنین در جاوا اسکریپت عدد صفر به false تفسیر می‌شود. بنابراین ترکیب true && 'Hi' && 1 مقدار 1 را بازگشت می‌دهد؛ چون عدد 1 هم از دیدگاه جاوا اسکریپت به true تفسیر خواهد شد.


مدیریت رخ‌دادها در React


همانطور که در تصویر فوق نیز مشاهده می‌کنید، رخ‌دادهای استاندارد DOM، دارای خواص معادل React ای نیز هستند. برای مثال زمانیکه می‌نویسیم onClick، دقیقا متناظر است با یک خاصیت المان React در عبارات JSX. بنابراین این نام‌ها حساس به کوچکی و بزرگی حروف نیز هستند.
روش تعریف متدهای رخ‌دادگردان در اینجا، با ذکر فعل handle شروع می‌شود:
  handleIncrement() {
    console.log("Increment clicked!");
  }
سپس ارجاعی از این متد را (نه فراخوانی آن‌را)، به خاصیت برای مثال onClick ارسال می‌کنیم:
<button
    onClick={this.handleIncrement}
    className="btn btn-secondary btn-sm"
>
    Increment
</button>
اگر دقت کنید، onClick، ارجاع this.handleIncrement را دریافت کرده‌است (یعنی بدون () ذکر شده‌است) و نه فراخوانی این متد را (با ذکر ()).
اکنون اگر این فایل را ذخیره کرده و خروجی را در مرورگر بررسی کنیم، با هربار کلیک بر روی دکمه‌ی Increment، یک console.log صورت می‌گیرد.

در ادامه می‌خواهیم در این رخ‌دادگردان، مقدار this.state.count را افزایش دهیم. برای این منظور ابتدا مقدار this.state.count را به نحو زیر لاگ می‌کنیم:
  handleIncrement() {
    console.log("Increment clicked!", this.state.count);
  }
پس از ذخیره‌ی فایل و اجرای برنامه، اینبار با کلیک بر روی دکمه‌ی Increment، بلافاصله خطای «Uncaught TypeError: Cannot read property 'state' of undefined» در کنسول توسعه دهنده‌های مرورگر ظاهر می‌شود. عنوان می‌کند که شیء this در این متد، undefined است؛ بنابراین امکان خواندن خاصیت state از آن وجود ندارد.


bind مجدد شیء this در رخ‌دادگردان‌های React

در مورد this و bind مجدد آن در مطلب «React 16x - قسمت 2 - بررسی پیشنیازهای جاوا اسکریپتی - بخش 1» مفصل بحث کردیم و در اینجا می‌خواهیم از نتایج آن استفاده کنیم.
همانطور که مشاهده کردید، در متد رویدادگران handleIncrement، به شیء this دسترسی نداریم. چرا؟ چون this در جاوا اسکریپت نسبت به سایر زبان‌های برنامه نویسی، متفاوت رفتار می‌کند. بسته به اینکه یک متد یا تابع، چگونه فراخوانی می‌شود، this می‌تواند اشیاء متفاوتی را بازگشت دهد. اگر تابعی به عنوان یک متد و جزئی از یک شیء فراخوانی شود، this در این حالت همواره ارجاعی را به آن شیء باز می‌گرداند. اما اگر آن تابع به صورت متکی به خود فراخوانی شد، به صورت پیش‌فرض ارجاعی را به شیء سراسری window مرورگر، بازگشت می‌دهد و اگر strict mode فعال باشد، تنها undefined را بازگشت می‌دهد. به همین جهت است که در اینجا خطای undefined بودن this را دریافت می‌کنیم.
یک روش حل این مشکل که پیشتر نیز در مورد آن توضیح دادیم، استفاده از متد bind است:
  constructor() {
    super();
    console.log("constructor", this);
    this.handleIncrement = this.handleIncrement.bind(this);
  }
زمانیکه شیءای از نوع کلاس جاری ایجاد می‌شود، متد constructor آن نیز فراخوانی خواهد شد. در این مرحله دسترسی کاملی به شیء this وجود دارد که نمونه‌ی آن‌را با console.log نوشته شده می‌توانید آزمایش کنید. در اینجا چون کامپوننت جاری از کلاس Component مشتق شده‌است، پیش از دسترسی به شیء this، نیاز است سازنده‌ی کلاس پایه توسط متد super فراخوانی شود. اکنون که به this دسترسی داریم، می‌توان توسط متد bind، مقدار شیء this شیءای دیگر مانند this.handleIncrement را تنظیم مجدد کنیم (متدها نیز در جاوا اسکریپت شیء هستند). خروجی آن، یک وهله‌ی جدید از شیء handleIncrement است که this آن اینبار به وهله‌ای از شیء جاری اشاره می‌کند. به همین جهت خروجی آن‌را به this.handleIncrement انتساب می‌دهیم تا مشکل تعریف نشده بودن this آن برطرف شود.
اکنون اگر برنامه را اجرا کنید، با کلیک بر روی دکمه‌ی Increment، بجای this.state.count لاگ شده، مقدار آن که صفر است، در کنسول توسعه دهنده‌های مرورگر ظاهر می‌شود.


این یک روش است که کار می‌کند؛ اما کمی طولانی است و به ازای هر روال رویدادگردانی باید دقیقا به همین نحو تکرار شود. روش دیگر، تبدیل متد handleIncrement به یک arrow function است و همانطور که در قسمت دوم این سری نیز بررسی کردیم، arrow functionها، this شیء جاری را بازنویسی نمی‌کنند؛ بلکه آن‌را به ارث می‌برند. بنابراین ابتدا کدهای سازنده‌ی فوق را حذف می‌کنیم (چون دیگر نیازی به آن‌ها نیست) و سپس متد handleIncrement سابق را به صورت زیر، تبدیل به یک arrow function می‌کنیم:
  handleIncrement = () => {
    console.log("Increment clicked!", this.state.count);
  }
به این ترتیب با کلیک بر روی دکمه‌ی Increment، مجددا همان خروجی تصویر قبلی را دریافت می‌کنیم؛ این روش ساده‌تر و تمیزتر است و نیازی به rebind دستی تک تک رویدادگردان‌های کامپوننت جاری در این حالت وجود ندارد.


به روز رسانی state در کامپوننت‌های React

اکنون که در روال رویدادگردان handleIncrement به شیء this و سپس مقدار this.state.count آن دسترسی پیدا کرده‌ایم، می‌خواهیم با هربار کلیک بر روی این دکمه، یک واحد مقدار آن‌را افزایش داده و در UI نمایش دهیم.
در React، خواص شیء state را جهت نمایش آن‌ها در UI، مستقیما تغییر نمی‌دهیم. به عبارت دیگر نوشتن یک چنین کدی در React برای به روز رسانی UI، مرسوم نیست:
  handleIncrement = () => {
    this.state.count++;
  };
اگر تغییر فوق را اعمال و سپس برنامه را اجرا کنید، با کلیک بر روی دکمه‌ی Increment ... اتفاقی رخ نمی‌دهد! رفتار React با Angular متفاوت است و در اینجا هرچند توسط فراخوانی {()this.formatCount} کار نمایش خاصیت count انجام می‌شود، اما به ظاهر، تغییرات مقدار count، به عبارات JSX متصل نیست. در کامپوننت‌های Angular اگر مقدار خاصیتی را تغییر دهید و اگر این خاصیت در قالب آن کامپوننت، به آن خاصیت bind شده باشد، شاهد به روز رسانی آنی UI خواهید بود (Change Detection آنی و به ازای هر تغییری)؛ اما در React خیر. هرچند در همان Angular هم توصیه می‌شود که از حالت changeDetection: ChangeDetectionStrategy.OnPush برای رسیدن به حداکثر کارآیی نمایشی کامپوننت‌ها استفاده شود؛ حالت OnPush در Angular، به روش تشخیص تغییرات React که در ادامه توضیح داده می‌شود، بیشتر شبیه است.

در کدهای فوق هرچند با کلیک بر روی دکمه‌ی Increment، مقدار count افزایش یافته‌است، اما React از وقوع این تغییرات مطلع نیست. به همین جهت است که هیچ تغییری را در UI برنامه مشاهده نمی‌کنید.
با اجرای قطعه کد فوق، یک چنین اخطاری نیز در کنسول توسعه دهندگان مرورگر ظاهر می‌شود:
  Line 33:5:  Do not mutate state directly. Use setState()  react/no-direct-mutation-state

برای رفع این مشکل باید از یکی از متدهای به ارث برده شده‌ی از کلاس پایه‌ی Component، به نام setState استفاده کرد. به این ترتیب به React اعلام می‌کنیم که state تغییر کرده‌است (فعالسازی Change Detection، فقط در صورت نیاز). سپس React شروع به محاسبه‌ی تغییرات کرده و در نتیجه قسمت‌های متناظری از UI را برای هماهنگ سازی DOM مجازی خودش با DOM اصلی، به روز رسانی می‌کند.
زمانیکه از متد setState استفاده می‌کنیم، شیءای را باید به صورت یک پارامتر به آن ارسال کنیم. در این حالت مقادیر آن یا به خاصیت state جاری اضافه می‌شوند و یا در صورت از پیش موجود بودن، همان خواص را بازنویسی می‌کنند:
  handleIncrement = () => {
    this.setState({ count: this.state.count + 1 });
  };
در اینجا به متد this.setState که از قسمت extends Component جاری به ارث رسیده‌است، یک شیء را با خاصیت count و مقدار جدیدی، ارسال می‌کنیم.
در این مرحله، فایل جاری را ذخیره کرده و پس از بارگذاری مجدد برنامه در مرورگر، بر روی دکمه‌ی Increment کلیک کنید. اینبار ... کار می‌کند! چون React از تغییرات مطلع شده‌است:


وقتی state تغییر می‌کند، چه اتفاقاتی رخ می‌دهند؟

با فراخوانی متد this.setState، به React اعلام می‌کنیم که state یک کامپوننت قرار است تغییر کند. سپس React فراخوانی مجدد متد Render را در صف اجرایی خودش قرار می‌دهد تا در زمانی در آینده، اجرا شود؛ این فراخوانی async است. کار متد render، بازگشت یک المان جدید React است. در اینجا DOM مجازی React از چند المان، به صورت یک div و دو فرزند دکمه و span تشکیل شده‌است. در این حالت یک DOM مجازی قدیمی نیز از قبل (پیش از اجرای مجدد متد render) وجود دارد. در این لحظه، React این دو DOM مجازی را کنار هم قرار می‌دهد و محاسبه می‌کند که در اینجا دقیقا کدام المان‌ها نسبت به قبل تغییر کرده‌اند. برای نمونه در اینجا تشخیص می‌دهد که span است که تغییر کرده، چون مقدار count، توسط آن نمایش داده می‌شود. در این حالت از کل DOM اصلی، تنها همان span تغییر کرده را به روز رسانی می‌کند و نه کل DOM را (و نه اعمال مجدد کل المان‌های حاصل از متد render را).
این مورد را می‌توان به نحو زیر آزمایش و مشاهده کرد:
در مرورگر بر روی المان span که شماره‌ها را نمایش می‌دهد، کلیک راست کرده و گزینه‌ی inspect را انتخاب کنید. سپس بر روی دکمه‌ی Increment کلیک نمائید. مرورگر قسمتی را که به روز می‌شود، با رنگی مشخص و متمایز، به صورت لحظه‌ای نمایش می‌دهد:



ارسال پارامترها به متدهای رویدادگردان

تا اینجا متد handleIncrement، بدون پارامتر تعریف شده‌است. فرض کنید در یک برنامه‌ی واقعی قرار است با کلیک بر روی این دکمه، id یک محصول را نیز به handleIncrement، منتقل و ارسال کنیم. اما در onClick={this.handleIncrement} تعریف شده، یک ارجاع را به متد handleIncrement داریم. بنابراین برای حل این مساله نمی‌توان از روشی مانند onClick={this.handleIncrement(1)} استفاده کرد که در آن عدد فرضی 1 به صورت آرگومان متد handleIncrement ذکر شده‌است.
یک روش حل این مساله، تعریف متد دومی است که متد handleIncrement پارامتر دار را فراخوانی می‌کند:
  doHandleIncrement = () => {
    this.handleIncrement({ id: 1, name: "Product 1" });
  };
و در این حالت برای مثال متد handleIncrement یک شیء را پذیرفته‌است:
  handleIncrement = product => {
    console.log(product);
    this.setState({ count: this.state.count + 1 });
  };
سپس بجای تعریف onClick={this.handleIncrement}، از متد doHandleIncrement استفاده خواهیم کرد؛ یعنی onClick={this.doHandleIncrement}

هرچند این روش کار می‌کند، اما بیش از اندازه طولانی شده‌است. راه حل بهتر، استفاده از یک inline function است:
onClick={() => this.handleIncrement({ id: 1, name: "Product 1" })}
یعنی کل arrow function مربوط به doHandleIncrement را داخل onClick قرار می‌دهیم و چون یک سطری است، نیازی به ذکر {} و سمی‌کالن انتهای آن‌را هم ندارد.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: sample-04-part02.zip
نظرات مطالب
سفارشی سازی ASP.NET Core Identity - قسمت چهارم - User Claims
- فعال شدن آنالایزرها را بر اساس debug و یا release تنظیم کنید. وجود آن‌ها build را کند می‌کنند.
- ارتقاء سخت افزاری را هم فراموش نکنید. اگر 3 دقیقه طول می‌کشد، یعنی نیاز به یک سیستم بهتر هست و ... در سایت دیوار موارد دست دوم خوبی را با 4 میلیون تومان می‌توانید پیدا کنید که نمونه‌ی نو آن‌ها شاید بالای 20 میلیون تومن قیمت داشته باشند.
مطالب
کامپوننت‌ها در Vue.js
پیش‌تر در سایت مطالبی در رابطه با فریم‌ورک Vue.js منتشر شده‌است. در این مطلب می‌خواهیم نگاهی بر مفهوم کامپوننت‌ها در Vue بیندازیم و نحوه‌ی استفاده از آنها را بررسی کنیم.

قبل از معرفی کامپوننت‌ها اجازه دهید سیستم template در ویو را بررسی کنیم. سیستم template ویو براساس سینتکس HTML است:
new Vue({
  el: '#app',
  template: '<div>Hello DNT</div>'
});
البته استفاده از template کاملاً اختیاری است. بجای آن می‌توانیم از تابع رندر (همانند React) نیز استفاده کنیم:
new Vue({
    el: '#app',
    data() {
        return {
            blogTitle: 'DNT'
        }
    },
    render: function (createElement) {
        return createElement('h1', this.blogTitle)
    }
});

ایجاد یک کامپوننت ساده:
Vue.component('child', {
    template: '<div>Hello DNT users</div>'
});
در اینجا برای ایجاد یک کامپوننت، از تابع component استفاده کرده‌ایم؛ پارامتر اول این تابع، نام کامپوننت است و پارامتر دوم نیز یک شیء است. درون این شیء می‌توانیم قالب کامپوننت را تعیین کنیم. برای کامپوننت نیز می‌توانیم یک پارامتر ورودی را تعیین کنیم. اینکار را توسط مفهومی به نام Props می‌توانیم انجام دهیم:
Vue.component('child', {
    props: ['text'],
    template: `<div> {{ text }} </div>`
});

new Vue({
    el: '#app',
    data() {
        return {
            message: 'Hello DNT!'
        }
    }
});
اکنون می‌توانیم پارامتر موردنظر را به text، به عنوان ورودی کامپوننت ارسال کنیم (در واقع دیتای موجود در parent را به کامپوننت child ارسال کرده‌ایم):
<child :text="message"></child>

اعتبارسنجی پراپرتی‌ها
برای props می‌توانیم اعتبارسنجی را نیز انجام دهیم:
Vue.component('blogPost', {
    props: {
        post: {
            type: Object,
            required: true
        }
    },
    template: `<div>
                    <h1>{{ post.title }}</h1>
                    <p>{{ post.body }}</p>
               </div>`
});
در اینجا نوع خاصیت post باید شیء باشد و همچنین آن را به صورت required تعریف کرده‌ایم. در این حالت اگر مقداری به غیر از شیء را به آن ارسال کنیم، خطای زیر را در کنسول دریافت خواهیم کرد:
[Vue warn]: Invalid prop: type check failed for prop "post". Expected Object, got String.

found in

---> <BlogPost>
       <Root>

همچنین می‌توانیم نوع اعتبارسنجی را به صورت سفارشی نیز تعیین کنیم:
Vue.component('blogPost', {
    props: {
        post: {
            type: Object,
            required: true,
            validator: obj => {
                const titleIsValid = typeof obj.title === 'string';
                const bodyIsValid = typeof obj.body === 'string';
                const isValid = titleIsValid && bodyIsValid;
                if (!isValid) {
                    console.warn("prop is not valid");
                    return false;
                }
                return true;
            }
        }
    },
    template: `<div>
                    <h1>{{ post.title }}</h1>
                    <p>{{ post.body }}</p>
               </div>`
});

تعیین مقدار پیش‌فرض برای پراپرتی
برای یک prop می‌توانیم مقدار پیش‌فرضی را نیز تعیین کنیم. یعنی در صورت عدم ارسال شیء می‌توانیم تعیین کنیم که چه شیء‌ایی در حالت پیش‌فرض نمایش داده شود:
Vue.component('blogPost', {
    props: {
        post: {
            type: Object,
            validator: obj => {
                const titleIsValid = typeof obj.title === 'string';
                const bodyIsValid = typeof obj.body === 'string';
                const isValid = titleIsValid && bodyIsValid;
                if (!isValid) {
                    console.warn("prop is not valid");
                    return false;
                }
                return true;
            },
            default: function() {
                return {
                    title: 'Vue is fun!',
                    body: 'Vue is fun..................'
                }
            }
        }
    },
    template: `<div>
                    <h1>{{ post.title }}</h1>
                    <p>{{ post.body }}</p>
               </div>`
});

استفاده از دیتا درون کامپوننت
درون یک کامپوننت نیز می‌توانیم یکسری دیتا را تعریف کنیم. اما باید در نظر داشته باشید که هر وهله از کامپوننت، scope مجزای خودش را دارد. در نتیجه پیشنهاد میشود دیتا حتماً به صورت یک تابع تعریف شود و همچنین داده‌های درون آن نیز در scope کامپوننت تعریف شوند:
data: function () {
    return {
        stars: 5,
        hover: 5
    }
},
زیرا در صورت تعریف داده‌ها در خارج از scope کامپوننت، محتویات دیتا برای دیگر وهله‌های کامپوننت‌ها نیز به اشتراک گذاشته می‌شود. به عنوان مثال فرض کنید درون کامپوننت بلاگ‌پست، یک سیستم امتیاز دهی قرار داده‌ایم:
var dt = {
    stars: 5,
    hover: 5
};
Vue.component('blogPost', {
    data: function() {
        return dt;
    },
    props:  // as before...,

    template: `<div class="blog-post">
                    <h1>{{ post.title }}</h1>
                    <p>{{ post.body }}</p>
                    <div class="star-wrap">
                        <span v-for="n in 5"
                            class="star"
                            :class="{ full: hover >= n+1 }"
                            @click="stars = n+1"
                            @mouseover="hover = n+1"
                            @mouseout="hover = stars"
                        ></span>
                    </div>
               </div>`
});
در این حالت خروجی زیر را خواهیم داشت:



برای رفع این مشکل کافی است به اینصورت دیتا را تعریف کنیم:

Vue.component('blogPost', {
    data: function() {
        return {
             stars: 5,
             hover: 5
        }
    },
    props:  // as before...,
    template: // as before
});


تغییر دیتا درون کامپوننت‌ها

تا اینجا توانستیم از کامپوننت والد داده‌هایی را به کامپوننت‌های فرزند ارسال کنیم. اکنون می‌خواهیم قابلیت تغییر دیتای تعریف شده‌ی درون کامپوننت والد را درون کامپوننت‌ها نیز داشته باشیم:

Vue.component('child', {
    props: ['message'],
    methods: {
        changeName() {
            this.message = "New Name!..."
        }
    },
    template: '#child-template'
});

new Vue({
    el: '#app',
    data() {
        return {
            name: 'DNT!'
        }
    }
});

تمپلیت کامپوننت فوق نیز به صورت x-template درون DOM تعریف شده است:

<script type="text/x-template" id="child-template">
    <div>
        <p>{{ message }}</p>
        <button @click="changeName">Change Name</button>
    </div>
</script>


فراخوانی کامپوننت نیز به اینصورت می‌باشد:

<div id="app">
    <child :message="name"></child>
</div>

همانطور که مشاهده می‌کنید، دیتای name را از طریق ویژگی message توانسته‌ایم به کامپوننت child ارسال کنیم. درون تمپلیت آن نیز یک دکمه را برای تغییر مقدار این ویژگی تعریف کرده‌ایم. تغییر این ویژگی نیز یک assignment ساده است. اما اگر بر روی دکمه‌ی Change Name کلیک کنید، هشدار زیر را درون کنسول مشاهده خواهید کرد:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "message"

found in

---> <Child>
       <Root>

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

changeName() {
    this.message = "New Name!...",
    this.$emit("change-name", this.message);
}

برای تگ child نیز این ایونت را اضافه خواهیم کرد:

<child :message="name" @change-name="name = $event"></child>

در اینحالت با تغییر ویژگی message، مقدار دیتای name نیز بلافاصله تغییر پیدا خواهد کرد.


Slots

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

<modal>
    Hello
</modal>

در اینحالت باید درون تمپلیت مکان قرارگیری Hello را تعیین کنیم. اینکار را می‌توانیم با قرار دادن تگ slot انجام دهیم:

Vue.component('modal', {
    template: `
            ...
            <div class="modal-body">
                <slot></slot>
            </div>
            ...
    `
});

اکنون هر محتوایی که درون تگ modal قرار گیرد، در قسمت slot نمایش داده خواهد شد. این نوع slot به صورت پیش‌فرض می‌باشد. در واقع می‌توانیم slotها را نیز نامگذاری کنیم. به عنوان مثال یک slot برای عنوان modal، یک slot برای بدنه modal و یک slot دیگر برای فوتر modal تعریف کنیم:

Vue.component('modal', {
    template: `
    <div class="modal fade" id="detailsModal" tabindex="-1" role="dialog" aria-labelledby="detailsModalLabel" aria-hidden="false">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="detailsModalLabel">
                        <slot name="title"></slot>
                    </h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    <slot name="body"></slot>
                </div>
                <div class="modal-footer">
                    <slot name="footer"></slot>
                </div>
            </div>
        </div>
        </div>
    `
});

اکنون می‌توانیم محتوای مورد نظر را برای قرارگیری درون slotها تعیین کنیم:

<modal>
    <template slot="title">Title</template>
    <template slot="body">Lorem ipsum dolor sit amet.</template>
    <template slot="footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
    </template>
</modal>


مطالب
پشتیبانی از SIMD در دات نت 4.6
SIMD مخفف «Single Instruction, Multiple Data» است و متشکل است از تعدادی instruction پردازنده‌ها که بجای مقادیر عددی، بر روی بردارها کار می‌کنند. به این ترتیب امکان کار موازی بر روی مقادیر عددی، در سطح CPU میسر می‌شود. برای نمونه به تصویر ذیل دقت کنید:


در اینجا قرار است تک تک عناصر آرایه‌ای از اعداد، با عدد 6 جمع شوند. روش متداول آن به این صورت است که حلقه‌ای تشکیل شده و سپس تک تک عناصر این آرایه دریافت و با عدد 6 جمع می‌شوند. اما در حالت استفاده‌ی از SIMD، هربار گروهی از عناصر این آرایه به صورت یک بردار درنظر گرفته می‌شوند (Multiple Data) و سپس با برداری حاوی مقدار 6 جمع می‌شوند (Single Instruction). اینبار این عملیات به صورت موازی، بر روی گروهی از اعداد انجام می‌شود و به همین دلیل نسبت به حالت کار بر روی یک المان از آرایه در هر مرحله، سرعت بیشتری دارد.


تفاوت چندریسمانی با SIMD چیست؟

شاید عنوان کنید که با وجود امکانات چندریسمانی چه نیازی به SIMD است؟ در حالت پردازش‌های چند ریسمانی، یک یا چند کار بر روی چندین هسته‌ی CPU به صورت موازی پردازش می‌شوند، اما SIMD امکان پردازش موازی را در یک هسته‌ی CPU میسر می‌کند.


آیا CPU من از SIMD پشتیبانی می‌کند؟

SIMD instruction sets شامل افزونه‌ها‌ی ذیل است:
• MMX - MultiMedia eXtensions
• SSE - Streaming SIMD Extensions
• SSE2 - Streaming SIMD Extensions 2
• SSE3 - Streaming SIMD Extensions 3
• SSSE3 - Supplemental Streaming SIMD Extensions 3
• SSE4.1 - Streaming SIMD Extensions 4.1
• SSE4.2 - Streaming SIMD Extensions 4.2
• AES-NI - Advanced Encryption Standard New Instructions
• AVX - Advanced Vector eXtensions
اگر CPU شما حداقل یکی از این قابلیت‌ها را داشته باشد، امکان استفاده‌ی از SIMD را دارید. برای مشخص سازی آن نیز می‌توانید از برنامه‌ی معروف CPU-Z استفاده کنید:


در این برنامه، در برگه‌ی CPU آن به قسمت instructions آن دقت کنید و موارد لیست شده‌ی در آن را با افزونه‌ها‌ی فوق مقایسه نمائید.


پشتیبانی از SIMD در دات نت

با ارائه‌ی دات نت 4.6 و RyuJIT جدید آن، امکان کار با دستورات SIMD در فضای نام System.Numerics.Vectors پیش بینی شده‌است. برای کار با آن باید بسته‌ی نیوگت زیر را نصب کنید:
 PM> Install-Package System.Numerics.Vectors
در ابتدای کار باید بررسی کنید که آیا سخت افزار شما از SIMD پشتیبانی می‌کند یا خیر. خاصیت Vector.IsHardwareAccelerated بیانگر این موضوع است. اما ... این خاصیت در حال دیباگ ممکن است مساوی false باشد. برای استفاده‌ی از SIMD ، طی این مراحل ضروری است:
الف) نصب دات نت 4.6.x (دریافت دات نت 4.6.1 مخصوص یکپارچه شدن با ویژوال استودیو)
ب) به خواص پروژه‌ی جاری مراجعه کرده و platform target را بر روی x64 قرار دهید. باید دقت داشت که RyuJIT جدید، برای سیستم‌های 64 بیتی طراحی شده‌است.
ج) RyuJIT، در حالت release و انتخاب گزینه‌ی optimize code (در همان برگه‌ی خواص پروژه) است که کدهای ویژه‌ی SIMD را تولید می‌کند.
د) نصب بسته‌ی نیوگت System.Numerics.Vectors

در کل اگر برنامه را داخل دیباگر VS.NET اجرا کنید، مقدار Vector.IsHardwareAccelerated مساوی false خواهد بود. به همین جهت برنامه را در حالت release و 64 بیتی کامپایل کرده و خارج از محیط VS.NET اجرا کنید.


بررسی فضای نام جدید System.Numerics.Vectors

پشتیبانی از SIMD در دات نت به این معنا نیست که هر نوع کدی توسط RyuJIT به صورت خودکار تبدیل به SIMD instruction sets خواهد شد. برای این منظور نیاز است از نوع‌های داده‌ای خاصی به همراه متدهای مرتبط با آن‌ها استفاده کرد.
سری اول این نوع‌های جدید برداری، به شرح زیر هستند:
var vector01 = new Vector2(x: 5F, y: 15F);
var vector11 = new Vector3(x: 5F, y: 15F, z: 25F);
var vector12 = new Vector3(x: 3F, y: 5F, z: 8F);
var vector13 = new Vector4(x: 3F, y: 5F, z: 8F, w:1F);
کلاس‌های وکتور 2، 3 و 4، بردارهایی از نوع float را با اندازه‌هایی ثابت تعریف می‌کنند و بر روی 128bit SIMD registers کار می‌کنند. بر روی این کلاس‌ها، با توجه به operators overloading صورت گرفته، امکان جمع، منها، ضرب و تقسیم نیز وجود دارد و یا می‌توان از متدهای متناظر موجود در کلاس‌های آن‌ها استفاده کرد. نمونه‌ای از این عملیات را در مثال‌های ذیل مشاهده می‌کنید:
var vector3 = vector11 - vector12; //استفاده از سربارگذاری عملگرها
var vector4 = Vector3.Subtract(vector12, vector11);//ویا استفاده از متدهای متناظر
 
vector3 = vector11 * vector12;
vector4 = Vector3.Multiply(vector11, vector12);
 
vector3 = vector11 / vector12;
vector4 = Vector3.Divide(vector11, vector12);
 
vector3 = vector11 + vector12;
vector4 = Vector3.Add(vector11, vector12);
 
var areEqual = (vector11 == vector12);
 
var areNotEqual = (vector11 != vector12);
 
var array = new float[3];
vector11.CopyTo(array);
در مثال آخر مطرح شده، روشی کپی و تبدیل یک بردار، به یک آرایه‌ی هم نوع آن، ارائه شده‌است.
علاوه بر اعمال متداول ریاضی، هر کدام از کلاس‌های Vector دارای متدهای اضافی ویژه‌ای مانند محاسبه‌ی حداقل، حداکثر، جذر و غیره نیز می‌باشند:
vector3 = Vector3.Max(vector11, vector12);
vector3 = Vector3.Min(vector11, vector12);
vector3 = Vector3.SquareRoot(vector11);
vector3 = Vector3.Abs(vector11);
var dotProduct = Vector3.Dot(vector11, vector12);
برای مثال متد Max در اینجا به MAXPS instruction مخصوص پردازشگر ترجمه می‌شود.

سری دوم بردارهای قابل تعریف، از نوع <Vector<T هستند. برای مثال CPUهایی که از SSE2 پشتیبانی می‌کنند، قابلیت کار با نوع‌های داده‌ای زیر را نیز دارا هستند:
Vector<double>.Length: 2
Vector<int>.Length: 4
Vector<long>.Length: 2
Vector<float>.Length: 4
برای نمونه همان مثال ابتدای بحث را در نظر بگیرید. نسخه‌ی متداول انجام افزودن مقداری به تک تک اعضای یک آرایه به صورت زیر است:
private static int[] simpleIncrement(int[] values, int inc)
{
    var results = new int[values.Length];
    for (var i = 0; i < results.Length; i++)
    {
        results[i] = values[i] + inc;
    }
    return results;
}
بازنویسی این متد برای کار با SIMD به صورت ذیل خواهد بود:
private static int[] simdIncrement(int[] values, int inc)
{
    var vector = new Vector<int>(values);
    var vectorAddResults = vector + new Vector<int>(inc);
 
    var results = new int[values.Length];
    vectorAddResults.CopyTo(results);
    return results;
}
در اینجا یک Vector از نوع int تعریف شده و سپس بجای تشکیل یک حلقه، فقط کافی است بردار دیگری را حاوی عدد مشخص شده، به آن اضافه کنیم. در پایان برای تبدیل این بردار به آرایه‌ای از نوع int (در صورت نیاز) می‌توان از متد Copy استفاده کرد.

در مثال ذیل، نحوه‌ی انتخاب Multiple data (گروهی از اعداد، بجای تک عدد) و سپس اعمال یک تک instruction را ملاحظه می‌کنید:
var valuesIn = new float[] { 4f, 16f, 36f, 64f, 9f, 81f, 49f, 25f, 100f, 121f, 144f, 16f, 36f, 4f, 9f, 81f };
var valuesOut = new float[valuesIn.Length];
for (var i = 0; i < valuesIn.Length; i += Vector<float>.Count)
{
    var vectorIn = new Vector<float>(valuesIn, i);
    
    var vectorOut = Vector.SquareRoot(vectorIn);
    vectorOut.CopyTo(valuesOut, i);
}
در مثال فوق قصد داریم جذر تک تک عناصر آرایه‌ای را محاسبه کرده و سپس در آرایه‌ی دومی ثبت کنیم. بجای روش متداول مراجعه‌ی به تک تک عناصر آرایه‌ی ورودی، اینبار با استفاده از کلاس بردار، به اندازه‌ی طول بردار float، اطلاعات را در vectorIn ذخیره کرده و سپس به صورت یکجا به تک متد SquareRoot ارسال می‌کنیم. این متد در سمت CPU به معادل SQRTPS instruction ترجمه می‌شود و تنها یک instruction است.

یک مثال تکمیلی