۵ راه برای تبدیل کامپوننت‌های کلاس React به کامپوننت‌های تابعی
ﺯﻣﺎﻥ ﻣﻄﺎﻟﻌﻪ: 22 دقیقه

۵ راه برای تبدیل کامپوننت‌های کلاس React به کامپوننت‌های تابعی

در آخرین نسخه آلفا از React، یک مفهوم جدید به نام Hooks (هوک‌ها) معرفی شد. هوک‌ها برای رفع بسیاری از مشکلات در React به وجود آمدند. گرچه، در درجه اول به عنوان جایگزینی برای کلاس‌ها به کار برده می‌شوند. با استفاده از هوک‌ها، ما می‌توانیم یک سری کامپوننت‌های تابعی بسازیم که از state و متدهای lifecycle استفاده می‌کنند.

هوک‌ها نسبتا جدید هستند. در واقع، فعلا در مرحله پیشنهاد به سر می‌برند. گرچه، اگر می‌خواهید با آن‌ها کار کنید و نگاه نزدیک‌تری به آنچه که فراهم می‌کنند داشته باشید، هوک‌ها دسترس هستند. در حال حاضر هوک‌ها در React v16.7.0-alpha قابل استفاده می‌باشند.

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

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

جدول محتویات:

  1. کلاس بدون state یا متدهای lifecycle
  2. کلاس به همراه state
  3. کلاس به همراه چندین ویژگی state
  4. کلاس به همراه  stateو componentDidMount
  5. کلاس به همراه state، componentDidMount و componentDidUpdate
  6. تبدیل PureComponent به React memo
  7. نتیجه گیری

کلاس بدون state یا متدهای lifecycle

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

import React, { Component } from 'react';

class App extends Component {

  alertName = () => {

    alert('John Doe');

  };

  render() {

    return (

      <div>

        <h3> This is a Class Component </h3>

        <button onClick={this.alertName}> Alert </button>

      </div>

    );

  }

}

export default App;

در اینجا ما یک کلاس React‌ معمولی داریم، و هیچ چیز جدید یا غیر معمولی در آن وجود دارد. این کلاس هیچ‌گونه state یا متد lifecycleای در خود ندارد. فقط وقتی که بر روی یک دکمه کلیک شده است، این کلاس یک نام را نشان می‌دهد. معادل تابعی این کلاس، چنین چیزی خواهد بود:

import React from 'react';

function App() {

  const alertName = () => {

    alert(' John Doe ');

  };

  return (

    <div>

      <h3> This is a Functional Component </h3>

      <button onClick={alertName}> Alert </button>

    </div>

  );

};

export default App;

به مانند کامپوننت کلاسی که پیش‌تر داشتیم، در اینجا هیچ چیز جدید یا غیر طبیعی‌ای وجود ندارد. ما هنوز حتی از هوک‌ها یا چیز دیگری هم استفاده نکرده‌ایم. علت آن این است که ما فقط مثالی را در نظر گرفته‌ایم که در آن نیازی به state یا lifecycle نداریم. اما حال بیایید آن را تغییر دهیم و به موقعیت‌هایی که یک کامپوننت بر پایه کلاس به همراه state داریم، و نحوه تبدیل آن به یک کامپوننت تابعی با استفاده از هوک‌ها نگاهی داشته باشیم.

کلاس به همراه state

بیایید موقعیتی را در نظر بگیریم که یک متغیر نام، (name) از نوع global داریم و می‌توانیم آن را داخل برنامه از طریق یک فیلد ورودی متن بروزرسانی کنیم. در React، ما موقعیت‌های این چنینی را با تعریف متغیر نام در آبجکت state و فراخوانی setState()، وقتی که یک مقدار جدید داریم تا متغیر name را با آن بروزرسانی کنیم، انجام می‌دهیم.

import React, { Component } from 'react';

class App extends Component {

state = {

      name: ''

  }

  alertName = () => {

    alert(this.state.name);

  };

  handleNameInput = e => {

    this.setState({ name: e.target.value });

  };

  render() {

    return (

      <div>

        <h3> This is a Class Component </h3>

        <input

          type="text"

          onChange={this.handleNameInput}

          value={this.state.name}

          placeholder="Your name"

        />

        <button onClick={this.alertName}> Alert </button>

      </div>

    );

  }

}

export default App;

وقتی که یک کاربر یک نام را در فیلد ورودی تایپ می‌کند و بر روی دکمه Alert کلیک می‌کند، نامی که در state تعریف کرده‌ایم را نمایش می‌دهد. باز هم این یک مفهوم React ساده است. گرچه، ما می‌توانیم کل این کلاس را با استفاده از هوک‌ها و به این صورت، تبدیل به یک کامپوننت تابعی React کنیم:

با استفاده از هوک‌های این چنینی، یک کلاس کامل را تبدیل به یک کامپوننت تابعی نمایید:

import React, { useState } from 'react';

function App() {

  const [name, setName] = useState('John Doe');

  const alertName = () => {

    alert(name);

  };

  const handleNameInput = e => {

    setName(e.target.value);

  };

  return (

    <div>

      <h3> This is a Functional Component </h3>

      <input

        type="text"

        onChange={handleNameInput}

        value={name}

        placeholder="Your name"

      />

      <button onClick={alertName}> Alert </button>

    </div>

  );

};

export default App;

در اینجا ما هوک useState را معرفی کردیم. این کار، حکم راهی برای استفاده از state در کامپوننت‌های تابعی React را دارد. با استفاده از هوک useState()، ما توانسته‌ایم که از state در این کامپوننت تابعی استفاده کنیم. این هوک از سینتکسی مشابه با تخریب اختصاص‌دهی برای آرایه‌ها استفاده می‌کند. این خط را در نظر بگیرید:

const [name, setName] = useState("John Doe")

در اینجا، name معادل this.state در یک کامپوننت کلاس معمولی بوده، و setName‌ معادل this.setState می‌باشد. آخرین چیز در هنگام استفاده از هوک setState()، این است که این هوک یک آرگومان را می‌گیرد که حکم مقدار اولیه state را در خود دارد. به زبان ساده، آرگومان useState() مقدار اولیه state است. در این مورد، ما آن را برابر با «John Doe» قرار می‌دهیم، که یعنی «John Doe» نام اولیه state است.

این نحوه تبدیل یک کامپوننت React بر پایه کلاس دارای state، به یک کامپوننت تابعی از طریق هوک‌ها است. چندین راه کاربردی دیگر برای انجام این کار وجود دارد، که ما در مثال‌های متعاقب خواهیم دید.

کلاس به همراه چندین ویژگی state

تبدیل یک ویژگی state با استفاده از useState ساده است، اما این روش وقتی که باید با چند ویژگی state سر و کله بزنید، پاسخگو نخواهد بود. برای مثال فرض کنید که ما دو یا چند فیلد ورودی برای userName، firstName و lastName، و یک کامپوننت بر پایه کلاس با سه ویژگی state به این صورت داریم:

import React, { Component } from 'react';

class App extends Component {

    state = {

      userName: '',

      firstName: '',

      lastName: ''

    };

  logName = () => {

    // هر کاری که می‌خواهید با نام‌ها انجام دهید، فقط به یاد داشته باشید که آن‌ها را در اینجا لاگ کنید

    console.log(this.state.userName);

    console.log(this.state.firstName);

    console.log(this.state.lastName);

  };

  handleUserNameInput = e => {

    this.setState({ userName: e.target.value });

  };

  handleFirstNameInput = e => {

    this.setState({ firstName: e.target.value });

  };

  handleLastNameInput = e => {

    this.setState({ lastName: e.target.value });

  };

  render() {

    return (

      <div>

        <h3> This is a Class Component </h3>

        <input

          type="text"

          onChange={this.handleUserNameInput}

          value={this.state.userName}

          placeholder="Your username"

        />

        <input

          type="text"

          onChange={this.handleFirstNameInput}

          value={this.state.firstName}

          placeholder="Your firstname"

        />

        <input

          type="text"

          onChange={this.handleLastNameInput}

          value={this.state.lastName}

          placeholder="Your lastname"

        />

        <button className="btn btn-large right" onClick={this.logName}>

          {' '}

          Log Names{' '}

        </button>

      </div>

    );

  }

}

export default App;

برای تبدیل این کلاس به یک کامپوننت تابعی با استفاده از هوک‌ها، باید یک راه نسبتا غیر متعارف را در پیش بگیریم. مثال بالا با استفاده از هوک useState()، می‌تواند به این صورت نوشته شود:

import React, { useState } from 'react';

function App() {

  const [userName, setUsername] = useState('');

  const [firstName, setFirstname] = useState('');

  const [lastName, setLastname] = useState('');

  const logName = () => {

    // هر کاری که می‌خواهید با نام‌ها انجام دهید، فقط به یاد داشته باشید که آن‌ها را در اینجا لاگ کنید

    console.log(userName);

    console.log(firstName);

    console.log(lastName);

  };

  const handleUserNameInput = e => {

    setUsername(e.target.value);

  };

  const handleFirstNameInput = e => {

    setFirstname(e.target.value);

  };

  const handleLastNameInput = e => {

    setLastname(e.target.value);

  };

  return (

    <div>

      <h3> This is a functional Component </h3>

      <input

        type="text"

        onChange={handleUserNameInput}

        value={userName}

        placeholder="username..."

      />

      <input

        type="text"

        onChange={handleFirstNameInput}

        value={firstName}

        placeholder="firstname..."

      />

      <input

        type="text"

        onChange={handleLastNameInput}

        value={lastName}

        placeholder="lastname..."

      />

      <button className="btn btn-large right" onClick={logName}>

        {' '}

        Log Names{' '}

      </button>

    </div>

  );

};

export default App;

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

این مثال را می‌توانید در این لینک و بر روی Codesandbox مشاهده کنید.

کلاس به همراه  stateو componentDidMount

بیایید کلاسی را فقط با state و componentDidMount‌ فرض کنیم. برای نمایش یک کلاس این چنینی، بیایید سناریو‌ای بسازیم که در آن state اولیه را برای سه فیلد ورودی تعیین می‌کنیم و پس از ۵ ثانیه، همه آن‌ها را به مقادیر دیگری تبدیل می‌کنیم.

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

import React, { Component, useEffect } from 'react';

class App extends Component {

    state = {

      // initial state

      userName: 'JD',

      firstName: 'John',

      lastName: 'Doe'

  }

  componentDidMount() {

    setInterval(() => {

      this.setState({

        // update state

        userName: 'MJ',

        firstName: 'Mary',

        lastName: 'jane'

      });

    }, 5000);

  }

  logName = () => {

    // هر کاری که می‌خواهید با نام‌ها انجام دهید، فقط به یاد داشته باشید که آن‌ها را در اینجا لاگ کنید

    console.log(this.state.userName);

    console.log(this.state.firstName);

    console.log(this.state.lastName);

  };

  handleUserNameInput = e => {

    this.setState({ userName: e.target.value });

  };

  handleFirstNameInput = e => {

    this.setState({ firstName: e.target.value });

  };

  handleLastNameInput = e => {

    this.setState({ lastName: e.target.value });

  };

  render() {

    return (

      <div>

        <h3> The text fields will update in 5 seconds </h3>

        <input

          type="text"

          onChange={this.handleUserNameInput}

          value={this.state.userName}

          placeholder="Your username"

        />

        <input

          type="text"

          onChange={this.handleFirstNameInput}

          value={this.state.firstName}

          placeholder="Your firstname"

        />

        <input

          type="text"

          onChange={this.handleLastNameInput}

          value={this.state.lastName}

          placeholder="Your lastname"

        />

        <button className="btn btn-large right" onClick={this.logName}>

          {' '}

          Log Names{' '}

        </button>

      </div>

    );

  }

}

export default App;

وقتی که برنامه اجرا می‌شود، فیلدهای ورودی مقادیر اولیه‌ای که در آبجکت state تعریف کرده‌ایم را خواهند داشت. سپس این مقادیر پس از ۵ ثانیه به مقادیری که داخل متد componentDidMount‌ تعریف کرده‌ایم، بروزرسانی خواهند شد. حال، بیایید با استفاده از هوک‌های useState و useEffect در React، این کلاس را به یک کامپوننت تابعی تبدیل کنیم.

import React, { useState, useEffect } from 'react';

function App() {

  const [userName, setUsername] = useState('JD');

  const [firstName, setFirstname] = useState('John');

  const [lastName, setLastname] = useState('Doe');

  useEffect(() => {

    setInterval(() => {

      setUsername('MJ');

      setFirstname('Mary');

      setLastname('Jane');

    }, 5000);

  });

  const logName = () => {

    // هر کاری که می‌خواهید با نام‌ها انجام دهید، فقط به یاد داشته باشید که آن‌ها را در اینجا لاگ کنید

    console.log(this.state.userName);

    console.log(this.state.firstName);

    console.log(this.state.lastName);

  };

  const handleUserNameInput = e => {

    setUsername({ userName: e.target.value });

  };

  const handleFirstNameInput = e => {

    setFirstname({ firstName: e.target.value });

  };

  const handleLastNameInput = e => {

    setLastname({ lastName: e.target.value });

  };

  return (

    <div>

      <h3> The text fields will update in 5 seconds </h3>

      <input

        type="text"

        onChange={handleUserNameInput}

        value={userName}

        placeholder="Your username"

      />

      <input

        type="text"

        onChange={handleFirstNameInput}

        value={firstName}

        placeholder="Your firstname"

      />

      <input

        type="text"

        onChange={handleLastNameInput}

        value={lastName}

        placeholder="Your lastname"

      />

      <button className="btn btn-large right" onClick={logName}>

        {' '}

        Log Names{' '}

      </button>

    </div>

  );

};

export default App;

این کامپوننت دقیقا کار کامپوننت قبلی را انجام می‌دهد. تنها تفاوت این است که به جای استفاده از آبجکت state مرسوم و متد componentDidMount‌ که در کامپوننت کلاس انجام دادیم، در اینجا از هوک‌های useState و useEffect استفاده می‌کنیم. صفحه Codesandbox این مثال را می‌توانید در این لینک بیابید.

کلاس به همراه state، componentDidMount و componentDidUpdate

سپس بیایید به یک کلاس React و دو متد lifecycle مختلف نگاه داشته باشیم. تا به اینجا ممکن است متوجه شده باشید که ما بیشتر در حال کار با هوک useState بوده‌ایم. در این مثال، بیایید بیشتر به هوک useEffect‌ نگاه داشته باشیم.

برای نمایش نحوه کار آن، بیایید کد خود را بروزرسانی کنیم تا به طور دینامیک هِدِر <h3>‌ صفحه‌مان را بروزرسانی کند. در حال حاضر header‌ می‌گوید: «This is a Class Component». حال ما یک متد componentDidMount() تعریف خواهیم کرد تا header را بروزرسانی نماید، و پس از سه ثانیه متن «Welcome to React Hooks» را نشان دهد.

import React, { Component } from 'react';

class App extends Component {

state = {

      header: 'Welcome to React Hooks'

  }

  componentDidMount() {

    const header = document.querySelectorAll('#header')[0];

    setTimeout(() => {

      header.innerHTML = this.state.header;

    }, 3000);

  }

  logName = () => {

    // هر کاری که می‌خواهید با نام‌ها انجام دهید، فقط به یاد داشته باشید که آن‌ها را در اینجا لاگ کنید

  };

  // { ... }

  render() {

    return (

      <div>

        <h3 id="header"> This is a Class Component </h3>

        <input

          type="text"

          onChange={this.handleUserNameInput}

          value={this.state.userName}

          placeholder="Your username"

        />

        <input

          type="text"

          onChange={this.handleFirstNameInput}

          value={this.state.firstName}

          placeholder="Your firstname"

        />

        <input

          type="text"

          onChange={this.handleLastNameInput}

          value={this.state.lastName}

          placeholder="Your lastname"

        />

        <button className="btn btn-large right" onClick={this.logName}>

          {' '}

          Log Names{' '}

        </button>

      </div>

    );

  }

}

export default App;

در این نقطه وقتی که برنامه اجرا می‌شود، با header اولیه «This is a Class Component» شروع می‌شود و پس از سه ثانیه به «Welcome to React Hooks» تغییر می‌کند. از آنجایی که این اتفاق پس از این که تابع رندر با موفقیت به اتمام رسیده است اجرا می‌شود، این در واقع رفتار componentDidMount() کلاسیک است.

اگر بخواهیم به طور دینامیک header را از یک فیلد ورودی دیگر بروزرسانی کنیم، به صورتی که همزمان با تایپ کردن ما header با متن بروزرسانی شود چه؟ برای انجام این کار، باید همچنین متد lifecycle با نام componentDidUpdate() را نیز پیاده‌سازی کنیم:

import React, { Component } from 'react';

class App extends Component {

  state = {

      header: 'Welcome to React Hooks'

  }

  componentDidMount() {

    const header = document.querySelectorAll('#header')[0];

    setTimeout(() => {

      header.innerHTML = this.state.header;

    }, 3000);

  }

  componentDidUpdate() {

    const node = document.querySelectorAll('#header')[0];

    node.innerHTML = this.state.header;

  }

  logName = () => {

    // هر کاری که می‌خواهید با نام‌ها انجام دهید، فقط به یاد داشته باشید که آن‌ها را در اینجا لاگ کنید

    console.log(this.state.username);

  };

  // { ... }

  handleHeaderInput = e => {

    this.setState({ header: e.target.value });

  };

  render() {

    return (

      <div>

        <h3 id="header"> This is a Class Component </h3>

        <input

          type="text"

          onChange={this.handleUserNameInput}

          value={this.state.userName}

          placeholder="Your username"

        />

        <input

          type="text"

          onChange={this.handleFirstNameInput}

          value={this.state.firstName}

          placeholder="Your firstname"

        />

        <input

          type="text"

          onChange={this.handleLastNameInput}

          value={this.state.lastName}

          placeholder="Your lastname"

        />

        <button className="btn btn-large right" onClick={this.logName}>

          {' '}

          Log Names{' '}

        </button>

        <input

          type="text"

          onChange={this.handleHeaderInput}

          value={this.state.header}

        />{' '}

      </div>

    );

  }

}

export default App;

در اینجا ما state، componentDidMount() و componentDidUpdate() را داریم. تا به اینجا وقتی که برنامه را اجرا می‌کنید، همانطور که پیش‌تر تعریف کردیم، header‌ پس از سه ثانیه به «Welcome to React Hooks» بروزرسانی می‌شود. سپس وقتی که شروع به تایپ کردن فیلد ورودی متن header می‌نمایید، متن <h3> همانطور که در متد componentDidUpdate() تعریف شد، با ورودی متن بروزرسانی می‌شود. حال بیایید این کلاس را با استفاده از هوک useEffect() به یک کامپوننت تابعی تبدیل کنیم.

import React, { useState, useEffect } from 'react';

function App() {

  const [userName, setUsername] = useState('');

  const [firstName, setFirstname] = useState('');

  const [lastName, setLastname] = useState('');

  const [header, setHeader] = useState('Welcome to React Hooks');

  const logName = () => {

    // هر کاری که می‌خواهید با نام‌ها انجام دهید، فقط به یاد داشته باشید که آن‌ها را در اینجا لاگ کنید

    console.log(userName);

  };

  useEffect(() => {

    const newheader = document.querySelectorAll('#header')[0];

    setTimeout(() => {

      newheader.innerHTML = header;

    }, 3000);

  });

  const handleUserNameInput = e => {

    setUsername(e.target.value);

  };

  const handleFirstNameInput = e => {

    setFirstname(e.target.value);

  };

  const handleLastNameInput = e => {

    setLastname(e.target.value);

  };

  const handleHeaderInput = e => {

    setHeader(e.target.value);

  };

  return (

    <div>

      <h3 id="header"> This is a functional Component </h3>

      <input

        type="text"

        onChange={handleUserNameInput}

        value={userName}

        placeholder="username..."

      />

      <input

        type="text"

        onChange={handleFirstNameInput}

        value={firstName}

        placeholder="firstname..."

      />

      <input

        type="text"

        onChange={handleLastNameInput}

        value={lastName}

        placeholder="lastname..."

      />

      <button className="btn btn-large right" onClick={logName}>

        {' '}

        Log Names{' '}

      </button>

      <input type="text" onChange={handleHeaderInput} value={header} />

    </div>

  );

};

export default App;

ما با استفاده از هوک useEffect()، به همان عملکرد مشابه رسیده‌ایم. از آنجایی که در اینجا مجبور نبودیم کد جداگانه‌ای برای componentDidMount() و componentDidUpdate() بنویسیم، این کد حتی مرتب‌تر و بهتر هم می‌شود. با استفاده از هوک useEffect()، ما می‌توانیم به هر دو عملکرد برسیم. علت آن این است که به طور پیشفرض، useEffect() هر دو را پس از رندر اولیه و هر بروزرسانی متعاقب اجرا می‌کند. این مثال را بر روی Codesandbox بررسی کنید.

تبدیل PureComponent به React memo

PureComponent در React،‌ به شیوه مشابه Component کار می‌کند. تفاوت اصلی میان آن‌ها، این است که React.Component، متد shouldComponentUpdate() را پیاده‌سازی نمی‌کند، در حالیکه React.PureComponent() این کار را انجام می‌دهد. اگر تابع render() برنامه شما، نتیجه مشابه را با propها و state مشابه رندر می‌کند، می‌توانید از React.PureComponent برای تسریع در کارایی برخی از موارد استفاده کنید. همین مسئله نسبت به React.memo() هم صدق می‌کند. مورد اول به کامپوننت‌های بر پایه کلاس اشاره دارد، و React memo هم به کامپوننت‌های تابعی اشاره دارد؛ به گونه‌ای که وقتی کامپوننت تابع شما نتیجه مشابه را رندر می‌کند، شما می‌توانید آن را در یک فراخوانی به React.memo() جمع‌بندی کنید تا کارایی را ارتقا دهید. استفاده از PureComponent و React.memo()، یک افزایش قابل توجه در کارایی را به برنامه می‌دهد، و همچنین تعداد عملیات‌های رندر را در برنامه کاهش می‌دهد.

در اینجا، ما نحوه تبدیل یک کلاس PureComponent به یک کامپوننت React memo را نمایش خواهیم داد. برای درک این که هر دوی آن‌ها دقیقا چگونه کار می‌کنند، در ابتدا بیایید یک موقعیت ناگوار را شبیه‌سازی کنیم که در آن یک کامپوننت هر دو ثانیه یک بار، چه تغییری در مقدار یا state به وجود آمده باشد یا چه نیامده باشد، رندر می‌شود. ما می‌توانیم این سناریو را به سرعت و به این صورت بسازیم:

import React, { Component } from 'react';

function Unstable(props) {

  // نشان دهید که این کامپوننت چند بار رندر شده است

  console.log(' Rendered this component ');

  return (

    <div>

      <p> {props.value}</p>

    </div>

  );

};

class App extends Component {

  state = {

    value: 1

  };

  componentDidMount() {

    setInterval(() => {

      this.setState(() => {

        return { value: 1 };

      });

    }, 2000);

  }

  render() {

    return (

      <div>

        <Unstable value={this.state.value} />

      </div>

    );

  }

}

export default App;

وقتی که برنامه را اجرا می‌کنید و لاگ‌ها را بررسی می‌کنید، متوجه خواهید شد که برنامه هر دو ثانیه بدون هیچ‌گونه تغییر در state یا propها، کامپوننت را رندر می‌کند. این سناریو هر چقدر هم که بد باشد، دقیقا سناریو‌ای است که ما می‌خواستیم بسازیم، و به شما نشان دهیم که چگونه هم PureComponent و هم React.memo() را برطرف کنیم.

اکثر مواقع، ما فقط می‌خواهیم یک کامپوننت را وقتی که تغییری در state یا propها بوده است، مجددا رندر کنیم. حال که این موقعیت ناگوار را تجربه کرده‌ایم، بیایید آن را با PureComponent برطرف کنیم، به گونه‌ای که کامپوننت فقط وقتی که تغییری در state یا propها به وجود آمده است، مجددا رندر شود. ما این کار را با وارد کردن PureComponent و گسترش آن به این صورت انجام می‌دهیم:

import React, { PureComponent } from 'react';

function Unstable(props) {

  console.log(' Rendered Unstable component ');

  return (

    <div>

      <p> {props.value}</p>

    </div>

  );

};

class App extends PureComponent {

  state = {

    value: 1

  };

  componentDidMount() {

    setInterval(() => {

      this.setState(() => {

        return { value: 1 };

      });

    }, 2000);

  }

  render() {

    return (

      <div>

        <Unstable value={this.state.value} />

      </div>

    );

  }

}

export default App;

حال اگر مجددا برنامه را اجرا کنید، فقط رندر اولیه را خواهید گرفت. پس از آن هیچ اتفاقی نمی‌افتد، چرا؟ خب، ما به جای class App extends Componnent{}، حال class App extends PureComponnent{} را داریم.

این کار، مشکل رندر مجدد کامپوننت‌های ما را بدون توجه به state فعلی برطرف می‌کند. گرچه، اگر ما این متد را:

componentDidMount() {

    setInterval(() => {

      this.setState(() => {

        return { value: 1 };

      });

    }, 2000);

  }

به این کد تغییر دهیم:

componentDidMount() {

    setInterval(() => {

      this.setState(() => {

        return { value: Math.random() };

      });

    }, 2000);

  }

کامپوننت هر زمان که مقدار مورد نظر به عدد تصادفی بعدی بروزرسانی شود، مجددا رندر خواهد شد. پس PureComponent، رندر کردن مجدد کامپوننت‌ها وقتی که تغییری در state یا propها بوده است را ممکن می‌کند. حال بیایید ببینیم که چگونه می‌توانیم از React.memo()‌ استفاده کنیم تا به همین نتیجه برسیم. برای انجام این کار با React memo، به سادگی و به این صورت کامپوننت را با استفاده از React.memo() جمع‌بندی کنید:

import React, { Component } from "react";

const Unstable = React.memo(function Unstable (props) {

  console.log(" Rendered Unstable component ");

  return <div>{props.val} </div>;

});

class App extends Component {

  state = {

    val: 1

  };

  componentDidMount() {

    setInterval(() => {

      this.setState({ val: 1 });

    }, 2000);

  }

  render() {

    return (

      <div>

        <header className="App-header">

          <Unstable val={this.state.val} />

        </header>

      </div>

    );

  }

}

export default App;

این کار، نتیجه مشابهی که PureComponent فراهم کرد را برای ما می‌آورد. از این رو، کامپوننت فقط پس از رندر اولیه رندر می‌شود و تا زمانی که تغییری در state را propها به وجود بیاید، مجددا رندر نمی‌شود. مثال Codesandbox را می‌توانید در این لینک بیابید.

نتیجه گیری

در این پست، ما چند روش برای تبدیل یک کلاس از پیش موجود بر پایه کامپوننت به یک کامپوننت تابعی با استفاده از هوک‌ها را نمایش دادیم. ما همچنین به یک موقعیت خاص تبدیل کلاس PureComponent به React.memo() نگاه داشته‌ایم. ممکن است که واضح باشد، اما همچنان حس می‌کنم نیاز است اشاره کنم که در جهت استفاده از هوک‌ها در برنامه خود، نیاز است که React خود را به نسخه پشتیبانی شده بروزرسانی کنید:

"react": "^16.7.0-alpha",

"react-dom": "^16.7.0-alpha",

React Hooks هنوز در مرحله پیشنهاد است. گرچه، امیدواریم که بخشی از نسخه پایدار بعدی باشد؛ زیرا ما را قادر می‌سازد که کیک خود را بخوریم (از state در کامپوننت‌های تابعی استفاده کنیم) و هنوز آن را داشته باشیم. (سادگی نوشتن کامپوننت‌های تابعی را نگه داریم)

منبع

چه امتیازی برای این مقاله میدهید؟

خیلی بد
بد
متوسط
خوب
عالی
در انتظار ثبت رای

5 سال پیش
/@er79ka

دیدگاه و پرسش

برای ارسال دیدگاه لازم است وارد شده یا ثبت‌نام کنید ورود یا ثبت‌نام

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید