فصل جدید و تغییر ساختار پروژه!

New Chapter and Project Restructuring

23 بهمن 1399
فصل جدید و تغییر ساختار پروژه!

نگاهی اصولی تر به ساختار پروژه ها

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

نکته: کدهای مربوط به جلسات «اشکال زدایی» را از پروژه حذف کرده و به حالت قبلی برگردید.

در حال حاضر پروژه تمرینی ما بسیار ساده است و تنها دو کامپوننت (App و Person) دارد. ساختار این پروژه در حال حاضر خوب است اما می تواند بهتر هم باشد. سوال اصلی ما همیشه این است که چه چیزهایی باید کامپوننت جداگانه خودشان را بگیرند و چه چیزهایی باید درون کامپوننت های دیگر قرار بگیرند. به طور مثال در کامپوننت Person یک input داریم و از آنجا که این input به افراد وابسته است. اگر input شما کلی بود و می خواستید که آن را در تمام سطح برنامه تان استفاده کنید، بهتر است آن را جدا کنید اما برای پروژه ما که هر input مختص یک person است، ساختار فعلی مناسب می باشد. بنابراین کامپوننت Person ما نیازی به ساختاردهی خاصی ندارد.

اگر به کامپوننت App نگاه کنید متوجه می شوید که بسیار شلوغ است و انواع کدها را در آن نوشته ایم. به طور مثال اگر درون تابع render را نگاه کنید لیست person ها را درون شرط if می بینید اما چند خط بعد از آن دکمه Toggle Persons را نیز داریم. در این باره یک قانون طلایی وجود دارد: کامپوننت های container (یعنی کامپوننت هایی که state را مدیریت می کنند) باید تا حد امکان درگیر render کردن UI (شکل ظاهری برنامه) نشوند. بنابراین کدهای قسمت render آن ها باید تا حد امکان ساده باشد و کمتر از کدهای JSX استفاده کند.

پروژه ما در حال حاضر سالم است و کار می کند و اشکال ساختاری نیز ندارد اما در بهترین شکل خود نیز نمی باشد. بنابراین بهتر است کامپوننت App را به چند کامپوننت تقسیم کنیم. به طور مثال بهتر است یک کامپوننت را مخصوص لیستِ Person ها قرار دهیم. برای این کار درون پوشه src یک پوشه دیگر به نام Persons بسازید (به s جمع توجه داشته باشید) و درون آن هم فایل Persons.js را اضافه می کنیم. حالا بهتر است پوشه Person را به درون پوشه Persons انتقال دهیم تا ساختار مناسبی داشته باشیم.

حالت منطقی تر این است که پوشه Persons را نیز درون یک پوشه دیگر به نام components قرار دهیم بنابراین این پوشه را در src ایجاد کرده و Persons را درون آن می گذاریم. سپس درون پوشه components یک پوشه دیگر به نام Cockpit با فایلی به نام Cockpit.js ایجاد کنید. این پوشه قرار است یک کامپوننت جدید باشد.

یک پوشه دیگر درون src به نام assets ایجاد کنید؛ این پوشه مسئول نگهداری تصاویر، ویدیو ها و دیگر منابع برنامه است. سپس یک پوشه دیگر به نام container درون پوشه src ایجاد کنید. این پوشه مسئول نگهداری container های ما (مانند App.js و فایل CSS مربوط به آن) است. فایل App.test.js را نیز به درون این پوشه انتقال دهید.

با عوض کردن ساختار پوشه ها باید تمامی دستور های import را نیز تصحیح کنیم بنابراین فایل App.js را باز کنید و دستور Import مربوط به Person را بدین شکل تغییر دهید:

import Person from '../components/Persons/Person/Person';

حالا فایل Index.js را باز کرده و دستور import مربوط به App.js را به شکل زیر تغییر دهید:

import App from './containers/App';

حالا فایل Persons.js را باز کنید تا با هم کدهایش را بنویسیم. ما در فایل Persons قصد مدیریت state را نداریم بنابراین از کامپوننت های کاربردی استفاده می کنیم. تا اینجای کار تمام کامپوننت های کاربردی ما بدین شکل بوده اند:

const persons = (props) => {
    return();
}

اما اگر فقط قرار است که چیزی را Return کنیم می توانیم از حالت خلاصه ES6 استفاده کرده و آن را بدین شکل بنویسیم:

const persons = (props) => ();

قبلا در مورد این حالت خلاصه صحبت کردیم و گفتیم اگر فقط بخواهیم چیزی را return کنیم و شروع قسمت return شده با خود تابع در یک خط باشد می توانیم آن را به شکل بالا بنویسیم. برای راحتی کار می توانیم پرانتز را بشکنیم:

const persons = (props) => (
    
);

مهم این است که فقط قصد return کردن داشته باشیم (دستورات دیگری انجام ندهیم) و قسمت return شده در همان خط تعریف تابع شروع شود.

مثل همیشه react را هم import می کنیم:

import React from 'react';

const persons = (props) => (

);

برای نوشتن کدهای این تابع می توانیم قسمتی از کدهای تابع map را از فایل App.js کپی کرده و props را به آن اضافه کنیم:

const persons = (props) => (
    props.persons.map((person, index) => {
        return <Person
            click={() => this.deletePersonHandler(index)}
            name={person.name}
            age={person.age}
            key={person.id}
            changed={(event) => this.nameChangedHandler(event, person.id)} />
    })
);

از آنجایی که این کد یک دستور جاوا اسکریپت است و JSX نیست (تمام کدها درون تابع map قرار گرفته اند بنابراین همگی یک دستور جاوا اسکریپت محسوب می شوند) می توانیم پرانتزهای اطرافش را حذف کنیم:

const persons = (props) => props.persons.map((person, index) => {
    return <Person
        click={() => this.deletePersonHandler(index)}
        name={person.name}
        age={person.age}
        key={person.id}
        changed={(event) => this.nameChangedHandler(event, person.id)} />
})

از آنجایی که Person را استفاده می کنیم باید آن را import کنیم:

import Person from './Person/Person';

حالا باید متدهای deletePersonHandler و nameChangedHandler را تصحیح کنیم چرا که در حال حاضر به آن ها دسترسی نداریم. این متدها درون کلاسی در App.js نوشته شده بودند اما الان فقط یک تابع داریم. بنابراین:

const persons = (props) => props.persons.map((person, index) => {
    return <Person
        click={() => props.clicked(index)}
        name={person.name}
        age={person.age}
        key={person.id}
        changed={(event) => props.changed(event, person.id)} />
})

ما می توانیم به این متدها از طریق props دسترسی داشته باشیم. البته به جای نام متد باید از نام property استفاده کنیم که متد در آن قرار دارد. حالا کامپوننت خود را export می کنیم:

export default persons;

حالا باید کدها را از سمت دیگر آماده کنیم. به فایل App.js و قسمت شرط if بروید (تابع map). ما دیگر نیازی به کد نمایش persons نداریم بلکه باید از کامپوننت Persons استفاده کنیم بنابراین ابتدا آن را import می کنیم. همچنین دیگر به Person نیازی نداریم، بنابراین کد import آن را نیز حذف می کنیم:

import Persons from '../components/Persons/Persons';

به قسمت آخر App.js بروید. شرط if زیر را پیدا خواهید کرد:

if (this.state.showPersons) {
      persons = (
        <div>
          {this.state.persons.map((person, index) => {
            return <Person
              click={() => this.deletePersonHandler(index)}
              name={person.name}
              age={person.age}
              key={person.id}
              changed={(event) => this.nameChangedHandler(event, person.id)} />
          })}
        </div>
      );

      btnClass = classes.Red;
}

همانطور که گفتیم ما دیگر نیازی به این کد نداریم بلکه در این قسمت باید از کامپوننت Persons خود استفاده کنیم بنابراین آن را بدین شکل تغییر می دهیم:

if (this.state.showPersons) {
      persons = (
        <div>
          <Persons />
        </div>
      );

      btnClass = classes.Red;
}

بیایید دوباره به کامپوننت Persons در فایل Persons.js نگاه کنیم:

const persons = (props) => props.persons.map((person, index) => {
    return <Person
        click={() => props.clicked(index)}
        name={person.name}
        age={person.age}
        key={person.id}
        changed={(event) => props.changed(event, person.id)} />
})

همانطور که می بینید در این کد 3 عدد props وجود دارد:

  • مورد اول: persons
  • مورد دوم: clicked
  • مورد سوم: changed

اما هنوز آن ها را تعریف نکرده ایم بنابراین به قسمت قبلی در فایل App.js برگشته و کد شرط if را مانند من تغییر دهید:

if (this.state.showPersons) {
      persons = (
        <div>
          <Persons
          persons={this.state.persons}
          clicked={this.deletePersonHandler}
          changed={this.nameChangedHandler} />
        </div>
);

در اینجا سه props مورد نظر را تعریف کردیم.

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

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

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.