الگوهای ری اکت - ۴

تو این مقاله که آخرین قسمت از سری الگوهای ری اکت هست، میخوام در مورد بهترین روش های استفاده از امکانات و قدرت ری اکت صحبت کنم. استفاده از الگوهای ری اکت باعث میشه کدهایی بنویسیم که به لحاظ کارایی و خوانایی سطح بالاتری داشته باشند.

تو این مقاله قصد دارم الگوهای ری اکت رو با بیان ساده شرح بدم . این مقاله برداشت آزادی از سایت الگوهای ری اکت است.

برای مطالعه قسمت های قبلی:

http://vrgl.ir/u1wC0
http://vrgl.ir/3hD8V
http://vrgl.ir/Ahf19

سرفصل های این قسمت:
Container component , Higher-order component, State hoisting, Controlled input


الگوهای ری اکت
الگوهای ری اکت


استفاده از Container component

قبل از هر چیز، نگاهی به تعریف کانتینر داشته باشیم:

کانتینر ، وظیفه گرفتن دیتا و رندر کردن کامپوننت های مربوطه رو داره.

کامپوننت CommentList زیر رو در نظر بگیرید که با مپ زدن روی لیستی از کامنت ها، اسم نویسنده و متن نوشته شده رو نمایش میده:

const CommentList = ({ comments }) => (
  <ul>
    {comments.map(comment => (
      <li>
        {comment.body}-{comment.author}
      </li>
    ))}
  </ul>
);

می‌تونیم کانتینر جدیدی بنویسیم که وظیفه گرفتن اطلاعات و همچنین رندر کردن اونها رو داشته باشه. تو تکه کد زیر از ajax برای درخواست زدن به سرور استفاده شده. (البته می‌تونید از fetch و axios استفاده کنید)

class CommentListContainer extends React.Component {
  state = { comments: [] }
  componentDidMount() {
    $.ajax({   // اینکه اینجا چه اتفاقی داره می‌افته مهم نیست
      url: &quot/my-comments.json&quot,
      dataType: 'json',
      success: comments =>
        this.setState({comments: comments});
    })
  }

  render() {
    return <CommentList comments={this.state.comments} />
  }
}

با لود شدن این کامپننت، درخواست Ajax زده می‌شه و داده ها به استیت کامپوننت CommentListContainer فرستاده میشه .داده های این state به کامپوننت CommentList داده میشه تا اونجا رندر بشه.


استفاده از Higher-order component

قبل از هر چیز،‌ نگاهی به تعریف تابع مرتبه بالا داشته باشیم:

تابعی که تابع دیگری در ورودی می‌گیره و یا تابعی رو برمی‌گردونه

کامپوننت مرتبه بالا چیه؟

کامپوننت Greeting رو در نظر بگیرید:

const Greeting = ({ name }) => {
  if (!name) {
    return <div>Connecting...</div>;
  }
  return <div>Hi {name}!</div>;
};

اگر این کامپونننت، پراپسی به اسم name بگیره، اون اسم رو همراه با کلمه "سلام" به نمایش میزاره در غیر این صورت عبارت Connecting... رندر میشه.

حالا چه جوری کامپوننت مرتبه بالا رو پیاده سازی کنیم؟

const Connect = ComposedComponent =>
  class extends React.Component {
    constructor() {
      super();
      this.state = { name: &quot&quot };
    }

    componentDidMount() {
      // this would fetch or connect to a store
      this.setState({ name: &quotMichael&quot });
    }

    render() {
      return <ComposedComponent {...this.props} name={this.state.name} />;
    }
  };
  

تابع Connect کامپوننت ComposedComponent رو برمی‌گردونه. این کامپوننت، Name که به عنوان آرگومان بهش پاس می‌دیم رو می‌گیره (که اینجا Michael هست) و رندر می‌کنه.

آخرین قدم، قرار دادن کامپوننت Greeting در تابع Connect که قبلا نوشتیم ( به این کار می‌گیم رپ کردن). در نتیجه قبل از لود شدن کامپوننت، رو صفحه عبارت Connecting... و بعد از لود شدن صفحه عبارت Hi Michael نمایش داده می‌شود.

const ConnectedMyComponent = Connect(Greeting);

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



استفاده از State hoisting

کامپوننت های تابعی بر خلاف کلاس کامپوننت ها نمی‌تونن state داشته باشند ( تا قبل از اومدن ری اکت هوک این شکلی بود اما الان دیگه این جوری نیست)‌.

به کامپوننت Name دقت کنید. تابع به صورت پراپس به این کامپوننت پاس داده می‌شه. توی کامپوننت پدر هم این مقدار رو به پاس میدیم. به این کار state hoisting گفته می‌شه.

class NameContainer extends React.Component {
  render() {
    return <Name ={newName => alert(newName)} />;
  }
}

// کامپوننت اسم که به صورت فانکشنال نوشته شده
const Name = ({  }) => (
  <input ={e => (e.target.value)} />
);

مثال پایین که در واقع همون مثال کامل شده بالا هست به ما نشون میده که به چه سادگی می‌تونیم تغییرات استیت رو با کامپوننت Name که داشتیم همراه کنیم:

class NameContainer extends React.Component {
  constructor() {
    super();
    this.state = { name: &quot&quot };
  }

  render() {
    return <Name ={newName => this.setState({ name: newName })} />;
  }
}

در واقع state بجای اینکه توی کامپوننت Name باشه، به کانتینرش رسید. اینجوری به راحتی کامپوننت فانکشنالی نوشتیم که استیت نداره (ولی از طریق کانتینر بهش استیت دادیم) و بدون در نظر گرفتن مقدار همه جا کار می‌کنه !

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


استفاده از Controlled input

کامپوننت ساده و uncontrolled زیر رو در نظر بگیرید:

<input type=&quottext&quot />

می‌خواهیم این کامپوننت رو به کامپوننت Controlled تبدیل کنیم. با نوشتن state این کارو شروع می‌کنیم:

class ControlledNameInput extends React.Component {
  constructor() {
    super();
    this.state = { name: &quot&quot };  // قرار دادن یک اسم خالی برای نمایش مقدار اولیه 
  }

  render() {
    return <input type=&quottext&quot value={this.state.name} />;
  }
}

خوب تنها کاری که باید انجام بدیم، قرار دادن تابع هست که وظیفه تغییر state رو داره:

return (
  <input
    value={this.state.name}
    ={e => this.setState({ name: e.target.value })}
  />
);



این ۴ نوشته با اسم الگوی ری اکت همین جا به پایان می‌رسه، سعی کردم با بیانی ساده بنویسم. با گفتن نظراتون به بهتر شدن نوشته هام کمک کنید. ممنون

سایر مقاله های من در ویرگول:

http://vrgl.ir/YhkrX
http://vrgl.ir/JgETy
http://vrgl.ir/aE7sU


Follow me on social media
Telegram
Facebook
Twitter
Linkedin
Virgool