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

یک برگه از کتاب فارسی ری اکت :

https://github.com/nimahkh/Persian-react-book/blob/master/articles/reactjs/06_Components_in_React.md

کامپوننت ها قطعاتی هستند که میتوان از آن ها هرجایی در پروژه استفاده کرد و در اصطلاح reusable هستند .
در ری اکت دو نوع کامپوننت میتوان نوشت ، یکی به شکل تابع و دیگری به شکل کلاس (class components , functional components).
داخل مثال hello world که پیشتر نوشتیم ، از کلاس کامپوننت ها استفاده کردیم

مثال hello world

حالا میتونیم همین کد رو به شکل زیر به شکل functional component بنویسیم .

function App(props){

    return (
      <div className="App">
        <header className="App-header">
          <p>
            Hello World , Hello Iran .
          </p>
        </header>
      </div>
    );
}

export default App;

بعد از جایگزین کردن ، میبینید که اپ به درستی کار میکنه .

تفاوت میان کلاس و تابع

این سوال شاید پیش بیاد که کدوم حالت بهتره؟
استفاده از توابع از نظر سینتکسی خیلی راحت تر از کلاس ها هستند .
قبل از ری اکت 16.8 تنها دلیلی که میتوانست کلاس را برتر از توابع کند ، امکان نوشتن setState داخل کلاس ها بود .
اما با ایجاد hooks در ری اکت 16.8 این قابلیت پیش آمد که تمام life cycle ری اکت را در functional Components داشته باشید .
به کد زیر دقت کنید :

import React, { useState } from 'react';

function App() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button ={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

export default App;

اگر کد بالا را جایگزین کد App.js کنین میبینید که state ها به راحتی جایگزین میشن .

چرا از توابع استفاده کنیم؟

ری اکت برای تبدیل کردن کدها به یک نسخه قابل قبول در جاوا اسکریپت نیاز به یک کامپایلر دارد . این کامپایلر به نام babel شناخته شده .
اگر ما کدهای کلاس کامپوننت ها را با توابع در babel مقایسه کنیم ، متوجه میشیم که کلاس ها خروجی بسیار سنگینی نسبت به توابع دارند .

خروجی babel از کلاس کامپوننت
خروجی babel از توابع

با مقایسه خروجی ها متوجه حجم زیاد خروجی های کلاس کامپوننت ها میشویم .

چرخه کامپوننت ها

کامپوننت های ری اکت دارای چرخه های زیادی هستند . معروفترین ها را در این سند میگیم . اما باقی چرخه ها به علت deprecate شدن و یا کمتر استفاده شدن ، در این سند نیستند و ارجاع داده میشند به لینک ری اکت .

Mounting
  • constructor

در کلاس های constructor ها سازنده مقادیر پیشفرض کلاس هستند . کاری که constructor ها داخل شی گرایی در همه زبان ها کار مقدار سازی اولیه را بر عهده دارند .
داخل لایبرری ری اکت ، این تابع عمدتا به منظور تعریف state ها و bind کردن توابع داخل کلاس کاربرد دارد .

اما در مورد functional components این موارد به شکل ثابت ها تعریف میشوند .

مثال کلاس کامپوننت ها :

class A extends Component {

   constructor(props){
     super(props);
     this.state={
       grades:['a','b','c'],
       name : '',
       family : ''
     };
   }
   
   ...
}


مثال در توابع :

function A(props){
...
   const [grades , setGrades]=useState(['a','b','c']);
   const [name , setName]=useState('');
   const [family , setFamily]=useState('');
...

}


  • render

این تابع فقط داخل کلاس کامپوننت ها کاربرد دارد در واقع این تابع همراه خود this.props و this.state را به داخل بدنه کامپوننت میارد .

  • componentDidMount

این تابع زمانی که بارگذاری کامپوننت به صورت کامل به اتمام رسید ، کار خود را شروع میکند .
خیلی بهتر بخوایم بگیم ، زمانی که کامپوننت بارگزاری شود ، هر آنچه داخل این تابع باشد اتفاق میفتد . شبیه به کار در جاوا اسکریپت

Updating
  • shouldComponentUpdate(nextProps, nextState)

این تابع به کامپوننت ما میگه که زمانی که یک state به روز بشه ، کامپوننت رو مجدد render کن .
این تابع دو مقدار میگیره به اسم nextProps, nextState . در واقع بررسی میکنیم که state یا props به سمت کامپوننت میاد ، آیا با مقادیر قبلی یا هر شرط دیگری که ما میدونیم ، قابل بررسی هست و نیاز به بروزرسانی کامپوننت دارد یا خیر.

  • componentDidUpdate

اگر کامپوننت به روز شد و به روز رسانی موفقیت آمیز بود ، این تابع کار میکند و هر آنچه که در بدنه آن نوشته شده باشد اجرا میشود .

این تابع برای کلاس کامپوننت های نوشته شده است و برای توابع باید از useEffect که معادل این تابع است استفاده کنیم .

useEffect یک هوک برای سنجش تغییرات کامپوننت در کلاس های تابعی هست که کاری مشابه componentDidUpdate, componentWillUnmount , componentDidmount را انجام میدهد .

Unmounting
  • componentWillUnmount

این تابع در کلاس کامپوننت ها کاربرد دارد و وظیفه این را بر عهده دارد که بعد از خروج از کامپوننت ، یک سری عملیات انجام دهد .

عمدتا توابعی که به صورت async هستند ، بعد از خروج از کامپوننت ها همچنان به کار خود ادامه میدهند .
مثلا شما یک setInterval نوشتید که هر 10 ثانیه یک عملیاتی را انجام دهد . حالا از صفحه و کامپوننت خارج شدید . قاعدتا باید clearInterval اتفاق بیفتد . در غیر این صورت بدنه اینتروال همچنان ادامه خواهد داشت .
clearInetrval را در این تابع مینویسیم که به کامپوننت بگیم بعد از خروج ، حتما تابع async رو متوقف کن

Error Handling
  • componentDidCatch(error, info)

این تابع که به تازگی معرفی شده دو مقدار دارد . error, info . زمانی که یک خطایی در کامپوننت رخ دهد ، به کمک این تابع میتوانید جلو یک سری ارور ها و exception هایی که ری اکت به کاربر نمایش میدهد را بگیرید .

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // Example "componentStack":
    //   in ComponentThatThrows (created by App)
    //   in ErrorBoundary (created by App)
    //   in div (created by App)
    //   in App
    logComponentStackToMyService(info.componentStack);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children; 
  }
}