portaldacalheta.pt
  • หลัก
  • ทีมแบบกระจาย
  • เคล็ดลับและเครื่องมือ
  • ชีวิตนักออกแบบ
  • นวัตกรรม
ส่วนหน้าของเว็บ

Angular vs. React: แบบไหนดีกว่าสำหรับการพัฒนาเว็บ?



มีบทความมากมายที่ถกเถียงกันว่า React หรือ Angular เป็นตัวเลือกที่ดีกว่าสำหรับการพัฒนาเว็บ เรายังต้องการอีกหรือไม่?

เหตุผลที่ฉันเขียนบทความนี้เป็นเพราะไม่มี ที่ บทความ เผยแพร่แล้ว แล้วแม้ว่าจะมีข้อมูลเชิงลึกที่ยอดเยี่ยม แต่ก็เจาะลึกเพียงพอสำหรับนักพัฒนาส่วนหน้าที่ใช้งานได้จริงในการตัดสินใจว่าจะเลือกตัวใดที่เหมาะกับความต้องการของตน



ในบทความนี้คุณจะได้เรียนรู้ว่าทั้ง Angular และ React มีจุดมุ่งหมายเพื่อแก้ปัญหาส่วนหน้าที่คล้ายกันอย่างไรแม้ว่าจะมีปรัชญาที่แตกต่างกันมากก็ตามและการเลือกอย่างใดอย่างหนึ่งเป็นเพียงเรื่องของความชอบส่วนบุคคลเท่านั้น ในการเปรียบเทียบเราจะสร้างแอปพลิเคชั่นเดียวกันสองครั้งโดยใช้ Angular จากนั้นอีกครั้งด้วย React



Angular’s ​​Untimely ประกาศ

เมื่อสองปีก่อนฉันเขียนบทความเกี่ยวกับไฟล์ ตอบสนองระบบนิเวศ . ในประเด็นอื่น ๆ บทความนี้เป็นที่ถกเถียงกันอยู่ว่า Angular ได้กลายเป็นเหยื่อของ“ ความตายโดยการประกาศล่วงหน้า” ในตอนนั้นตัวเลือกระหว่าง Angular กับเกือบทุกอย่างเป็นเรื่องง่ายสำหรับทุกคนที่ไม่ต้องการให้โครงการของพวกเขาทำงานบนเฟรมเวิร์กที่ล้าสมัย Angular 1 ล้าสมัยและ Angular 2 ก็ไม่มีให้ใช้งานในเวอร์ชันอัลฟา



c corp vs s corp

ในการมองย้อนกลับไปความกลัวนั้นมีเหตุผลไม่มากก็น้อย Angular 2 เปลี่ยนไปอย่างมากและยังผ่านการเขียนซ้ำครั้งใหญ่ก่อนการเปิดตัวครั้งสุดท้าย

สองปีต่อมาเรามี Angular 4 พร้อมคำสัญญาว่าจะให้ความมั่นคงสัมพันธ์กันนับจากนี้เป็นต้นไป



ตอนนี้เป็นอย่างไร

Angular vs. React: การเปรียบเทียบแอปเปิ้ลและส้ม

บางคนบอกว่าการเปรียบเทียบ React กับ Angular ก็เหมือนกับการเปรียบเทียบแอปเปิ้ลกับส้ม ในขณะที่ไลบรารีหนึ่งคือไลบรารีที่เกี่ยวข้องกับมุมมอง แต่อีกอันเป็นเฟรมเวิร์กที่สมบูรณ์



แน่นอนที่สุด ตอบสนองนักพัฒนา จะเพิ่มไลบรารีสองสามไลบรารีเพื่อตอบสนองเพื่อเปลี่ยนเป็นเฟรมเวิร์กที่สมบูรณ์ จากนั้นอีกครั้งขั้นตอนการทำงานที่เป็นผลลัพธ์ของสแต็กนี้มักจะยังคงแตกต่างจาก Angular อยู่มากดังนั้นความสามารถในการเปรียบเทียบจึงยังคง จำกัด

ความแตกต่างที่ใหญ่ที่สุดอยู่ที่การจัดการของรัฐ Angular มาพร้อมกับการผูกข้อมูลที่รวมอยู่ในขณะที่ React ในปัจจุบันมักจะถูกเพิ่มโดย Redux เพื่อให้การไหลของข้อมูลทิศทางเดียวและทำงานกับข้อมูลที่ไม่เปลี่ยนทิศทาง สิ่งเหล่านี้กำลังต่อต้านแนวทางในสิทธิของตนเองและการอภิปรายนับไม่ถ้วนกำลังเกิดขึ้นว่าการผูกข้อมูลที่ไม่แน่นอน / ข้อมูลดีกว่าหรือแย่กว่าไม่เปลี่ยนทิศทาง / ทิศทางเดียว



สนามเล่นระดับ

เนื่องจาก React มีชื่อเสียงในการแฮ็คได้ง่ายขึ้นฉันจึงตัดสินใจสร้างการตั้งค่าการตอบสนองที่สะท้อน Angular อย่างใกล้ชิดเพื่อให้สามารถเปรียบเทียบข้อมูลโค้ดแบบเคียงข้างกันได้

คุณสมบัติเชิงมุมบางอย่างที่โดดเด่น แต่ไม่อยู่ในการตอบสนองตามค่าเริ่มต้นคือ:



ลักษณะเฉพาะ แพ็คเกจเชิงมุม ตอบสนองไลบรารี
การผูกข้อมูลการฉีดพึ่งพา (DI) @ เชิงมุม / แกน MobX
คุณสมบัติที่คำนวณ rxjs MobX
การกำหนดเส้นทางตามส่วนประกอบ @ เชิงมุม / เราเตอร์ ตอบสนองเราเตอร์ v4.0
ส่วนประกอบการออกแบบวัสดุ @ เชิงมุม / วัสดุ ตอบสนองกล่องเครื่องมือ
CSS กำหนดขอบเขตไว้ที่ส่วนประกอบ @ เชิงมุม / แกน โมดูล CSS
การตรวจสอบแบบฟอร์ม @ เชิงมุม / แบบฟอร์ม FormState
เครื่องกำเนิดโครงการ @ เชิงมุม / cli ตอบสนองสคริปต์ TS

การผูกข้อมูล

การผูกข้อมูลสามารถเริ่มต้นด้วยเนื้อหาได้ง่ายกว่าวิธีการแบบทิศทางเดียว แน่นอนมันเป็นไปได้ที่จะไปในทิศทางตรงกันข้ามอย่างสิ้นเชิงและใช้ Redux หรือ mobx รัฐต้นไม้ ด้วย React และ ngrx ด้วย Angular แต่นั่นจะเป็นหัวข้อสำหรับโพสต์อื่น

คุณสมบัติที่คำนวณ

ในขณะที่ประสิทธิภาพเป็นเรื่องที่น่ากังวล แต่การรับแบบธรรมดาใน Angular นั้นไม่ต้องสงสัยเลยเมื่อพวกเขาถูกเรียกในการแสดงผลแต่ละครั้ง เป็นไปได้ที่จะใช้ พฤติกรรม จาก RsJS ซึ่งทำงาน



ด้วย React คุณสามารถใช้ @ คอมพิวเตอร์ จาก MobX ซึ่งบรรลุวัตถุประสงค์เดียวกันโดยมี API ที่ดีกว่าเล็กน้อย

การฉีดพึ่งพา

การฉีดแบบพึ่งพาเป็นเรื่องที่ถกเถียงกันเพราะมันขัดกับกระบวนทัศน์การตอบสนองในปัจจุบันของการเขียนโปรแกรมเชิงฟังก์ชันและการไม่เปลี่ยนรูป ปรากฎว่าการแทรกซึมแบบพึ่งพาบางประเภทแทบจะขาดไม่ได้ในสภาพแวดล้อมการผูกข้อมูลเนื่องจากช่วยในการแยกส่วน (และการเยาะเย้ยและการทดสอบ) โดยที่ไม่มีสถาปัตยกรรมชั้นข้อมูลแยกต่างหาก

ข้อดีอีกอย่างของ DI (รองรับใน Angular) คือความสามารถในการมีวงจรชีวิตที่แตกต่างกันของร้านค้าต่างๆ กระบวนทัศน์การตอบสนองในปัจจุบันส่วนใหญ่ใช้สถานะแอปทั่วโลกบางประเภทซึ่งจับคู่กับส่วนประกอบต่างๆ แต่จากประสบการณ์ของฉันการแนะนำจุดบกพร่องทั้งหมดนั้นง่ายเกินไปเมื่อทำความสะอาดสถานะทั่วโลกในการยกเลิกการต่อเชื่อมส่วนประกอบ

การมีร้านค้าที่สร้างขึ้นจากการติดตั้งส่วนประกอบ (และสามารถใช้ได้อย่างราบรื่นสำหรับเด็ก ๆ ของส่วนประกอบนี้) ดูเหมือนจะมีประโยชน์มากและมักถูกมองข้ามแนวคิด

นอกกรอบใน Angular แต่สามารถทำซ้ำได้อย่างง่ายดายด้วย MobX เช่นกัน

การกำหนดเส้นทาง

การกำหนดเส้นทางตามคอมโพเนนต์ช่วยให้คอมโพเนนต์สามารถจัดการเส้นทางย่อยของตนเองแทนที่จะมีการกำหนดค่าเราเตอร์ส่วนกลางขนาดใหญ่เพียงรายการเดียว ในที่สุดแนวทางนี้ก็เป็น react-router ในเวอร์ชัน 4

การออกแบบวัสดุ

เป็นเรื่องดีเสมอที่จะเริ่มต้นด้วยส่วนประกอบระดับสูงขึ้นไปและการออกแบบวัสดุได้กลายเป็นสิ่งที่เหมือนกับตัวเลือกเริ่มต้นที่ยอมรับกันทั่วไปแม้ในโครงการที่ไม่ใช่ของ Google

ฉันจงใจเลือก ตอบสนองกล่องเครื่องมือ มากกว่าที่แนะนำโดยปกติ UI วัสดุ เนื่องจาก UI วัสดุได้สารภาพตัวเองอย่างจริงจัง ปัญหาด้านประสิทธิภาพ ด้วยแนวทาง inline-CSS ซึ่งพวกเขาวางแผนที่จะแก้ปัญหาในเวอร์ชันถัดไป

นอกจากนี้ PostCSS / cssnext ที่ใช้ใน React Toolbox กำลังเริ่มแทนที่ Sass / LESS อยู่ดี

CSS ที่กำหนดขอบเขต

คลาส CSS เป็นตัวแปรส่วนกลาง มีหลายวิธีในการจัดระเบียบ CSS เพื่อป้องกันความขัดแย้ง (รวมถึง ดี ) แต่มีแนวโน้มที่ชัดเจนในการใช้ไลบรารีที่ช่วยประมวลผล CSS เพื่อป้องกันความขัดแย้งเหล่านั้นโดยไม่ต้องใช้ไฟล์ นักพัฒนาส่วนหน้า เพื่อประดิษฐ์ระบบการตั้งชื่อ CSS อย่างละเอียด

การตรวจสอบแบบฟอร์ม

การตรวจสอบแบบฟอร์มเป็นคุณสมบัติที่ไม่สำคัญและใช้กันอย่างแพร่หลาย ดีที่มีไลบรารีอยู่เพื่อป้องกันการซ้ำซ้อนของโค้ดและบั๊ก

ตัวสร้างโครงการ

การมีเครื่องกำเนิด CLI สำหรับโปรเจ็กต์นั้นสะดวกกว่าการโคลนบอยเลอร์เพลทจาก GitHub

แอปพลิเคชันเดียวกันสร้างขึ้นสองครั้ง

ดังนั้นเราจะสร้างแอปพลิเคชันเดียวกันใน React และ Angular ไม่มีอะไรน่าตื่นเต้นมีเพียง Shoutboard ที่ให้ทุกคนสามารถโพสต์ข้อความไปยังเพจทั่วไป

คุณสามารถทดลองใช้งานได้ที่นี่:

  • Shoutboard Angular
  • ปฏิกิริยา Shoutboard

แอพพลิเคชัน Shoutboard

หากคุณต้องการมีซอร์สโค้ดทั้งหมดคุณสามารถรับได้จาก GitHub:

  • แหล่งที่มาของ Shoutboard Angular
  • แหล่งที่มาของปฏิกิริยา Shoutboard

คุณจะสังเกตเห็นว่าเราได้ใช้ TypeScript สำหรับแอป React ด้วย ข้อดีของการตรวจสอบประเภทใน TypeScript นั้นชัดเจน และตอนนี้เนื่องจากการจัดการการนำเข้าที่ดีขึ้น async / a waiting และ rest สเปรดก็มาถึง TypeScript 2 ในที่สุดก็ออกจาก Babel / ES7 / ไหล ในฝุ่น

นอกจากนี้เราจะเพิ่ม ลูกค้าของ Apollo ทั้งสองอย่างเพราะเราต้องการใช้ GraphQL ฉันหมายความว่า REST นั้นยอดเยี่ยมมาก แต่หลังจากผ่านไปสักสิบปีมันก็เก่าลง

Bootstrap และ Routing

ก่อนอื่นมาดูจุดเข้าใช้งานของทั้งสองแอปพลิเคชัน

เชิงมุม

const appRoutes: Routes = [ { path: 'home', component: HomeComponent }, { path: 'posts', component: PostsComponent }, { path: 'form', component: FormComponent }, { path: '', redirectTo: '/home', pathMatch: 'full' } ] @NgModule({ declarations: [ AppComponent, PostsComponent, HomeComponent, FormComponent, ], imports: [ BrowserModule, RouterModule.forRoot(appRoutes), ApolloModule.forRoot(provideClient), FormsModule, ReactiveFormsModule, HttpModule, BrowserAnimationsModule, MdInputModule, MdSelectModule, MdButtonModule, MdCardModule, MdIconModule ], providers: [ AppService ], bootstrap: [AppComponent] }) @Injectable() export class AppService { username = 'Mr. User' }

โดยพื้นฐานแล้วส่วนประกอบทั้งหมดที่เราต้องการใช้ในแอปพลิเคชันจำเป็นต้องไปที่การประกาศ ไลบรารีของบุคคลที่สามทั้งหมดที่จะนำเข้าและร้านค้าทั่วโลกทั้งหมดไปยังผู้ให้บริการ ส่วนประกอบของเด็ก ๆ สามารถเข้าถึงสิ่งเหล่านี้ได้โดยมีโอกาสที่จะเพิ่มสิ่งของในท้องถิ่นมากขึ้น

ตอบสนอง

const appStore = AppStore.getInstance() const routerStore = RouterStore.getInstance() const rootStores = { appStore, routerStore } ReactDOM.render( , document.getElementById('root') )

ส่วนประกอบนี้ใช้สำหรับการฉีดแบบพึ่งพาใน MobX จะบันทึกร้านค้าตามบริบทเพื่อให้ส่วนประกอบของปฏิกิริยาสามารถฉีดเข้าไปในภายหลังได้ ใช่บริบทการตอบสนองสามารถใช้ (เนื้อหา) ได้ อย่างปลอดภัย .

เวอร์ชัน React นั้นสั้นกว่าเล็กน้อยเนื่องจากไม่มีการประกาศโมดูล - โดยปกติคุณเพียงแค่นำเข้าและพร้อมใช้งาน บางครั้งการพึ่งพาอย่างหนักแบบนี้ไม่เป็นที่ต้องการ (การทดสอบ) ดังนั้นสำหรับร้านซิงเกิลตันทั่วโลกฉันต้องใช้อายุหลายสิบปีนี้ GoF รูปแบบ :

export class AppStore { static instance: AppStore static getInstance() @observable username = 'Mr. User' }

Angular’s ​​Router สามารถฉีดได้ดังนั้นจึงสามารถใช้งานได้จากทุกที่ไม่เพียง แต่ส่วนประกอบเท่านั้น เพื่อให้ได้ปฏิกิริยาเดียวกันเราใช้ mobx-react-router แพคเกจและฉีด routerStore.

สรุป: การบูตแอปพลิเคชันทั้งสองค่อนข้างตรงไปตรงมา React มีขอบที่ง่ายกว่าโดยใช้เพียงการนำเข้าแทนโมดูล แต่อย่างที่เราจะเห็นในภายหลังโมดูลเหล่านั้นมีประโยชน์มากทีเดียว การทำเสื้อกล้ามด้วยตนเองเป็นเรื่องที่น่ารำคาญเล็กน้อย สำหรับไวยากรณ์การประกาศเส้นทาง JSON เทียบกับ JSX เป็นเพียงเรื่องของการตั้งค่า

ลิงค์และการนำทางที่จำเป็น

ดังนั้นจึงมีสองกรณีสำหรับการเปลี่ยนเส้นทาง ประกาศโดยใช้ องค์ประกอบและความจำเป็นเรียก API การกำหนดเส้นทาง (และตำแหน่งที่ตั้ง) โดยตรง

เชิงมุม

Home Posts {this.props.children}

React Router ยังสามารถตั้งค่าคลาสของลิงค์ที่ใช้งานได้ด้วย activeClassName

ที่นี่เราไม่สามารถระบุชื่อคลาสได้โดยตรงเนื่องจากคอมไพเลอร์โมดูล CSS สร้างขึ้นโดยเฉพาะและเราจำเป็นต้องใช้ style ผู้ช่วย. เพิ่มเติมในภายหลัง

ดังที่เห็นด้านบน React Router ใช้องค์ประกอบภายใน anelement เนื่องจากองค์ประกอบเพียงแค่ห่อและต่อเชื่อมเส้นทางปัจจุบันหมายความว่าเส้นทางย่อยของส่วนประกอบปัจจุบันเป็นเพียง this.props.children นั่นก็ประกอบได้เช่นกัน

export class FormStore { routerStore: RouterStore constructor() { this.routerStore = RouterStore.getInstance() } goBack = () => { this.routerStore.history.push('/posts') } }

mobx-router-store แพ็คเกจยังช่วยให้การฉีดและการนำทางทำได้ง่าย

สรุป: ทั้งสองวิธีในการกำหนดเส้นทางมีความคล้ายคลึงกันมาก Angular ดูเหมือนจะใช้งานง่ายกว่าในขณะที่ React Router มีความสามารถในการประกอบที่ตรงไปตรงมากว่าเล็กน้อย

การฉีดพึ่งพา

ได้รับการพิสูจน์แล้วว่ามีประโยชน์ในการแยกชั้นข้อมูลออกจากชั้นการนำเสนอ สิ่งที่เราพยายามบรรลุด้วย DI ในที่นี้คือการสร้างส่วนประกอบของชั้นข้อมูล (ในที่นี้เรียกว่าโมเดล / ร้านค้า / บริการ) ตามวงจรชีวิตของส่วนประกอบภาพและทำให้สามารถสร้างส่วนประกอบดังกล่าวหนึ่งหรือหลายอินสแตนซ์ได้โดยไม่จำเป็นต้องสัมผัสทั่วโลก สถานะ. นอกจากนี้ควรผสมและจับคู่ข้อมูลและเลเยอร์การแสดงภาพที่เข้ากันได้

ตัวอย่างในบทความนี้ง่ายมากดังนั้นสิ่งต่างๆของ DI ทั้งหมดอาจดูเหมือนมากเกินไป แต่ก็มีประโยชน์เมื่อแอปพลิเคชันเติบโตขึ้น

เชิงมุม

@Injectable() export class HomeService { message = 'Welcome to home page' counter = 0 increment() { this.counter++ } }

ดังนั้นคลาสใดก็ได้ที่สามารถสร้าง @injectable และคุณสมบัติและวิธีการที่มีให้สำหรับส่วนประกอบ

@Component({ selector: 'app-home', templateUrl: './home.component.html', providers: [ HomeService ] }) export class HomeComponent { constructor( public homeService: HomeService, public appService: AppService, ) { } }

โดยการลงทะเบียน HomeService สำหรับคอมโพเนนต์ providers เราทำให้พร้อมใช้งานสำหรับคอมโพเนนต์นี้โดยเฉพาะ ตอนนี้ไม่ใช่ซิงเกิลตัน แต่แต่ละอินสแตนซ์ของคอมโพเนนต์จะได้รับสำเนาใหม่ที่เมาท์ของคอมโพเนนต์ นั่นหมายความว่าไม่มีข้อมูลเก่าจากการใช้งานครั้งก่อน

ในทางตรงกันข้าม AppService ได้รับการลงทะเบียนกับ app.module (ดูด้านบน) ดังนั้นจึงเป็นซิงเกิลตันและยังคงเหมือนเดิมสำหรับส่วนประกอบทั้งหมดแม้ว่าอายุการใช้งานของแอปพลิเคชัน ความสามารถในการควบคุมวงจรชีวิตของบริการจากส่วนประกอบเป็นแนวคิดที่มีประโยชน์มาก แต่ไม่ได้รับการชื่นชม

DI ทำงานโดยกำหนดอินสแตนซ์บริการให้กับตัวสร้างของคอมโพเนนต์ซึ่งระบุโดยประเภท TypeScript นอกจากนี้ public คีย์เวิร์ดจะกำหนดพารามิเตอร์ให้กับ this โดยอัตโนมัติเพื่อที่เราจะได้ไม่ต้องเขียนสิ่งที่น่าเบื่อ this.homeService = homeService เส้นอีกต่อไป

Dashboard


Clicks since last visit: {{homeService.counter}} Click!

ไวยากรณ์ของเทมเพลต Angular มีเนื้อหาค่อนข้างหรูหรา ฉันชอบ [()] ช็อตคัทซึ่งทำงานเหมือนการเชื่อมข้อมูลแบบ 2 ทาง แต่ภายใต้ประทุนนั้นแท้จริงแล้วมันคือแอ็ตทริบิวต์การโยง + เหตุการณ์ ตามวงจรชีวิตของบริการของเรา homeService.counter จะรีเซ็ตทุกครั้งที่เราออกจาก /home แต่ appService.username อยู่และสามารถเข้าถึงได้จากทุกที่

ตอบสนอง

import { observable } from 'mobx' export class HomeStore { @observable counter = 0 increment = () => { this.counter++ } }

ด้วย MobX เราต้องเพิ่ม @observable มัณฑนากรของสถานที่ให้บริการใด ๆ ที่เราต้องการให้สังเกตได้

@observer export class Home extends React.Component { homeStore: HomeStore componentWillMount() { this.homeStore = new HomeStore() } render() { return } }

ในการจัดการวงจรชีวิตอย่างถูกต้องเราต้องทำงานมากกว่าในตัวอย่าง Angular เล็กน้อย เราห่อ HomeComponent ภายใน a Provider ซึ่งได้รับอินสแตนซ์ใหม่ของ HomeStore ในแต่ละเมานต์

interface HomeComponentProps { appStore?: AppStore, homeStore?: HomeStore } @inject('appStore', 'homeStore') @observer export class HomeComponent extends React.Component { render() { const { homeStore, appStore } = this.props return

Dashboard

Clicks since last visit: {homeStore.counter} Click! } }

HomeComponent ใช้ @observer มัณฑนากรเพื่อรับฟังการเปลี่ยนแปลงใน @observable คุณสมบัติ.

กลไกใต้ฝากระโปรงของสิ่งนี้ค่อนข้างน่าสนใจดังนั้นเรามาดูคร่าวๆกันดีกว่า @observable มัณฑนากรแทนที่คุณสมบัติในออบเจ็กต์ด้วย getter และ setter ซึ่งอนุญาตให้ดักฟังการโทร เมื่อฟังก์ชันการแสดงผลของ @observer ส่วนประกอบที่เพิ่มขึ้นเรียกว่าคุณสมบัติเหล่านั้นจะถูกเรียกและพวกมันยังคงอ้างอิงถึงส่วนประกอบที่เรียกมัน

จากนั้นเมื่อมีการเรียกใช้ setter และมีการเปลี่ยนแปลงค่าฟังก์ชัน render ของส่วนประกอบที่ใช้คุณสมบัติในการเรนเดอร์ล่าสุดจะถูกเรียก ตอนนี้ข้อมูลเกี่ยวกับคุณสมบัติที่ใช้ในการอัปเดตและวงจรทั้งหมดสามารถเริ่มต้นใหม่ได้

กลไกที่ง่ายมากและมีประสิทธิภาพมากเช่นกัน คำอธิบายเชิงลึกเพิ่มเติม ที่นี่ .

@inject มัณฑนากรใช้ฉีด appStore และ homeStore อินสแตนซ์ในอุปกรณ์ประกอบฉากของ HomeComponent ณ จุดนี้แต่ละร้านมีวงจรชีวิตที่แตกต่างกัน appStore จะเหมือนกันในช่วงชีวิตของแอปพลิเคชัน แต่ homeStore ถูกสร้างขึ้นใหม่ในการนำทางไปยังเส้นทาง“ / home” แต่ละครั้ง

ข้อดีของการนี้คือไม่จำเป็นต้องทำความสะอาดคุณสมบัติด้วยตนเองเนื่องจากเป็นกรณีที่ร้านค้าทั้งหมดอยู่ทั่วโลกซึ่งเป็นเรื่องที่น่าปวดหัวหากเส้นทางเป็นหน้า 'รายละเอียด' บางส่วนที่มีข้อมูลที่แตกต่างกันอย่างสิ้นเชิงในแต่ละครั้ง

สรุป: เนื่องจากการจัดการวงจรชีวิตของผู้ให้บริการในคุณลักษณะโดยธรรมชาติของ Angular’s ​​DI แน่นอนว่าจะทำได้ง่ายกว่าที่นั่น นอกจากนี้ยังสามารถใช้เวอร์ชัน React ได้ แต่เกี่ยวข้องกับสำเร็จรูปมากกว่า

คุณสมบัติที่คำนวณ

ตอบสนอง

มาเริ่มกันที่ React ซึ่งมีวิธีแก้ปัญหาที่ตรงไปตรงมามากขึ้น

import { observable, computed, action } from 'mobx' export class HomeStore { import { observable, computed, action } from 'mobx' export class HomeStore { @observable counter = 0 increment = () => { this.counter++ } @computed get counterMessage() { console.log('recompute counterMessage!') return `${this.counter} ${this.counter === 1 ? 'click' : 'clicks'} since last visit` } }

ดังนั้นเราจึงมีคุณสมบัติที่คำนวณซึ่งเชื่อมโยงกับ counter และส่งกลับข้อความที่เป็นพหูพจน์อย่างถูกต้อง ผลลัพธ์ของ counterMessage ถูกแคชและจะคำนวณใหม่เมื่อ counter เท่านั้น การเปลี่ยนแปลง

{homeStore.counterMessage} Click!

จากนั้นเราอ้างอิงคุณสมบัติ (และ increment วิธีการ) จากเทมเพลต JSX ฟิลด์อินพุตถูกขับเคลื่อนโดยการผูกกับค่าและปล่อยให้เมธอดจาก appStore จัดการเหตุการณ์ของผู้ใช้

เชิงมุม

ภาษาโปรแกรม c คืออะไร

เพื่อให้ได้เอฟเฟกต์เดียวกันใน Angular เราต้องมีความคิดสร้างสรรค์มากขึ้น

import { Injectable } from '@angular/core' import { BehaviorSubject } from 'rxjs/BehaviorSubject' @Injectable() export class HomeService { message = 'Welcome to home page' counterSubject = new BehaviorSubject(0) // Computed property can serve as basis for further computed properties counterMessage = new BehaviorSubject('') constructor() { // Manually subscribe to each subject that couterMessage depends on this.counterSubject.subscribe(this.recomputeCounterMessage) } // Needs to have bound this private recomputeCounterMessage = (x) => { console.log('recompute counterMessage!') this.counterMessage.next(`${x} ${x === 1 ? 'click' : 'clicks'} since last visit`) } increment() { this.counterSubject.next(this.counterSubject.getValue() + 1) } }

เราจำเป็นต้องกำหนดค่าทั้งหมดที่ใช้เป็นพื้นฐานสำหรับคุณสมบัติที่คำนวณเป็น BehaviorSubject คุณสมบัติที่คำนวณเองก็เป็น BehaviorSubject เช่นกันเนื่องจากคุณสมบัติใด ๆ ที่คำนวณสามารถใช้เป็นอินพุตสำหรับคุณสมบัติที่คำนวณอื่นได้

แน่นอน RxJS ทำได้ ล้นหลาม มากกว่าแค่นี้ แต่นั่นจะเป็นหัวข้อสำหรับบทความที่แตกต่างไปจากเดิมอย่างสิ้นเชิง ข้อเสียเล็กน้อยคือการใช้ RxJS เพียงเล็กน้อยสำหรับคุณสมบัติที่คำนวณเพียงเล็กน้อยนั้นค่อนข้างละเอียดกว่าตัวอย่างปฏิกิริยาและคุณต้องจัดการการสมัครสมาชิกด้วยตนเอง (เช่นที่นี่ในตัวสร้าง)

{homeService.counterMessage } Click!

สังเกตว่าเราสามารถอ้างอิงหัวเรื่อง RxJS ด้วย | async ได้อย่างไร ท่อ. นั่นเป็นสัมผัสที่ดีสั้นกว่าที่ต้องสมัครสมาชิกในส่วนประกอบของคุณ input คอมโพเนนต์ขับเคลื่อนโดย [(ngModel)] คำสั่ง แม้จะดูแปลกตา แต่ก็ดูหรูหรามากทีเดียว เพียงแค่น้ำตาลเชิงไวยากรณ์สำหรับการผูกข้อมูลของค่ากับ appService.username และกำหนดค่าอัตโนมัติจากเหตุการณ์ป้อนข้อมูลของผู้ใช้

สรุป: คุณสมบัติที่คำนวณนั้นง่ายต่อการใช้งานใน React / MobX มากกว่าใน Angular / RxJS แต่ RxJS อาจมีคุณสมบัติ FRP ที่มีประโยชน์มากกว่าซึ่งอาจได้รับการชื่นชมในภายหลัง

เทมเพลตและ CSS

หากต้องการแสดงให้เห็นว่าเทมเพลตซ้อนทับกันอย่างไรให้ใช้คอมโพเนนต์โพสต์ที่แสดงรายการโพสต์

เชิงมุม

@Component({ selector: 'app-posts', templateUrl: './posts.component.html', styleUrls: ['./posts.component.css'], providers: [ PostsService ] }) export class PostsComponent implements OnInit { constructor( public postsService: PostsService, public appService: AppService ) { } ngOnInit() { this.postsService.initializePosts() } }

ส่วนประกอบนี้เชื่อมโยง HTML, CSS และบริการที่แทรกเข้าด้วยกันและยังเรียกใช้ฟังก์ชันเพื่อโหลดโพสต์จาก API ในการเริ่มต้น AppService เป็นซิงเกิลตันที่กำหนดไว้ในโมดูลแอปพลิเคชันในขณะที่ PostsService เป็นแบบชั่วคราวโดยมีอินสแตนซ์ใหม่ที่สร้างขึ้นในแต่ละครั้งที่สร้างส่วนประกอบ CSS ที่อ้างอิงจากคอมโพเนนต์นี้จะถูกกำหนดขอบเขตให้กับคอมโพเนนต์นี้ซึ่งหมายความว่าเนื้อหาไม่สามารถส่งผลกระทบใด ๆ นอกคอมโพเนนต์

add

Hello {{appService.username}}

{{post.title}} {{post.name}}

{{post.message}}

ในเทมเพลต HTML เราอ้างอิงส่วนประกอบส่วนใหญ่จาก Angular Material เพื่อให้พร้อมใช้งานจำเป็นต้องรวมไว้ใน app.module การนำเข้า (ดูด้านบน) *ngFor คำสั่งใช้เพื่อทำซ้ำ md-card ส่วนประกอบสำหรับแต่ละโพสต์

CSS ในเครื่อง:

.mat-card { margin-bottom: 1rem; }

CSS ในเครื่องเพียงแค่เพิ่มหนึ่งในคลาสที่มีอยู่บน md-card ส่วนประกอบ.

CSS ส่วนกลาง:

.float-right { float: right; }

คลาสนี้ถูกกำหนดใน global style.css ไฟล์เพื่อให้พร้อมใช้งานสำหรับส่วนประกอบทั้งหมด สามารถอ้างอิงได้ด้วยวิธีมาตรฐาน class='float-right'

CSS ที่รวบรวม:

.float-right { float: right; } .mat-card[_ngcontent-c1] { margin-bottom: 1rem; }

ใน CSS ที่คอมไพล์แล้วเราจะเห็นว่า CSS ในเครื่องถูกกำหนดขอบเขตไปยังส่วนประกอบที่แสดงผลโดยใช้ [_ngcontent-c1] ตัวเลือกแอตทริบิวต์ ทุกองค์ประกอบเชิงมุมที่แสดงผลมีคลาสที่สร้างขึ้นเช่นนี้เพื่อวัตถุประสงค์ในการกำหนดขอบเขต CSS

ข้อดีของกลไกนี้คือเราสามารถอ้างอิงคลาสได้ตามปกติและการกำหนดขอบเขตจะถูกจัดการ“ ภายใต้ประทุน”

ตอบสนอง

import * as style from './posts.css' import * as appStyle from '../app.css' @observer export class Posts extends React.Component { postsStore: PostsStore componentWillMount() { this.postsStore = new PostsStore() this.postsStore.initializePosts() } render() { return } }

ใน React อีกครั้งเราต้องใช้ Provider แนวทางการสร้าง PostsStore การพึ่งพา 'ชั่วคราว' นอกจากนี้เรายังนำเข้ารูปแบบ CSS ซึ่งอ้างอิงเป็น style และ appStyle เพื่อให้สามารถใช้คลาสจากไฟล์ CSS เหล่านั้นใน JSX

การปรับแต่งประสิทธิภาพใน sql server 2012
interface PostsComponentProps { appStore?: AppStore, postsStore?: PostsStore } @inject('appStore', 'postsStore') @observer export class PostsComponent extends React.Component { render() { const { postsStore, appStore } = this.props return

Hello {appStore.username}

{postsStore.posts.map(post => {post.message} )} } }

โดยปกติแล้ว JSX ให้ความรู้สึกกับ JavaScript-y มากกว่าเทมเพลต HTML ของ Angular ซึ่งอาจเป็นสิ่งที่ดีหรือไม่ดีขึ้นอยู่กับรสนิยมของคุณ แทน *ngFor คำสั่งเราใช้ map สร้างเพื่อวนซ้ำโพสต์

ตอนนี้ Angular อาจเป็นเฟรมเวิร์กที่ดึงดูด TypeScript มากที่สุด แต่จริงๆแล้วมันเป็น JSX ที่ TypeScript โดดเด่นจริงๆ ด้วยการเพิ่มโมดูล CSS (นำเข้าด้านบน) มันจะเปลี่ยนการเข้ารหัสเทมเพลตของคุณเป็นเซนการเติมโค้ด ทุกสิ่งจะถูกตรวจสอบประเภท ส่วนประกอบแอตทริบิวต์แม้แต่คลาส CSS (appStyle.floatRight และ style.messageCard ดูด้านล่าง) และแน่นอนลักษณะแบบลีนของ JSX สนับสนุนให้แบ่งออกเป็นส่วนประกอบและส่วนย่อยมากกว่าเทมเพลตของ Angular เล็กน้อย

CSS ในเครื่อง:

.messageCard { margin-bottom: 1rem; }

CSS ส่วนกลาง:

.floatRight { float: right; }

CSS ที่รวบรวม:

.floatRight__qItBM { float: right; } .messageCard__1Dt_9 { margin-bottom: 1rem; }

อย่างที่คุณเห็นตัวโหลดโมดูล CSS จะทำการแก้ไข CSS แต่ละคลาสด้วย postfix แบบสุ่มซึ่งรับประกันความเป็นเอกลักษณ์ วิธีที่ตรงไปตรงมาเพื่อหลีกเลี่ยงความขัดแย้ง จากนั้นคลาสจะถูกอ้างอิงผ่านอ็อบเจ็กต์ที่นำเข้า Webpack ข้อเสียเปรียบประการหนึ่งที่เป็นไปได้คือคุณไม่สามารถสร้าง CSS ด้วยคลาสและเพิ่มระดับได้เหมือนที่เราทำในตัวอย่าง Angular ในทางกลับกันนี่อาจเป็นสิ่งที่ดีเพราะมันบังคับให้คุณต้องห่อหุ้มสไตล์ให้เหมาะสม

สรุป: โดยส่วนตัวแล้วฉันชอบ JSX มากกว่าเทมเพลต Angular โดยเฉพาะอย่างยิ่งเนื่องจากการเติมโค้ดและการสนับสนุนการตรวจสอบประเภท นั่นเป็นคุณสมบัติของนักฆ่าจริงๆ ตอนนี้ Angular มีคอมไพเลอร์ AOT ซึ่งสามารถมองเห็นบางสิ่งได้เช่นกันการเติมโค้ดยังใช้งานได้ประมาณครึ่งหนึ่งของสิ่งที่นั่น แต่ยังไม่สมบูรณ์เท่า JSX / TypeScript

GraphQL - กำลังโหลดข้อมูล

ดังนั้นเราจึงตัดสินใจใช้ GraphQL เพื่อจัดเก็บข้อมูลสำหรับแอปพลิเคชันนี้ วิธีที่ง่ายที่สุดวิธีหนึ่งในการสร้างแบ็คเอนด์ของ GraphQL คือการใช้ BaaS บางตัวเช่น Graphcool นั่นคือสิ่งที่เราทำ โดยพื้นฐานแล้วคุณเพียงแค่กำหนดโมเดลและคุณสมบัติและ CRUD ของคุณก็พร้อมใช้งาน

รหัสทั่วไป

เนื่องจากโค้ดที่เกี่ยวข้องกับ GraphQL บางส่วนเหมือนกัน 100% สำหรับการใช้งานทั้งสองอย่างจึงไม่ควรทำซ้ำสองครั้ง:

const PostsQuery = gql` query PostsQuery { allPosts(orderBy: createdAt_DESC, first: 5) { id, name, title, message } } `

GraphQL เป็นภาษาสืบค้นที่มีวัตถุประสงค์เพื่อมอบชุดฟังก์ชันที่สมบูรณ์ยิ่งขึ้นเมื่อเทียบกับจุดสิ้นสุด RESTful แบบคลาสสิก มาดูคำค้นหานี้กัน

  • PostsQuery เป็นเพียงชื่อสำหรับการสืบค้นนี้เพื่ออ้างอิงในภายหลังสามารถตั้งชื่ออะไรก็ได้
  • allPosts เป็นส่วนที่สำคัญที่สุด - อ้างอิงถึงฟังก์ชันเพื่อสืบค้นระเบียนทั้งหมดด้วยโมเดล 'โพสต์' ชื่อนี้สร้างโดย Graphcool
  • orderBy และ first เป็นพารามิเตอร์ของ allPosts ฟังก์ชัน createdAt เป็นหนึ่งใน Post คุณลักษณะของโมเดล first: 5 หมายความว่าจะส่งคืนผลลัพธ์ 5 รายการแรกของข้อความค้นหา
  • id, name, title และ message เป็นคุณลักษณะของ Post แบบจำลองที่เราต้องการรวมไว้ในผลลัพธ์ แอตทริบิวต์อื่น ๆ จะถูกกรองออก

อย่างที่คุณเห็นแล้วว่ามันทรงพลังมาก เช็คเอาท์ หน้านี้ เพื่อทำความคุ้นเคยกับแบบสอบถาม GraphQL มากขึ้น

interface Post { id: string name: string title: string message: string } interface PostsQueryResult { allPosts: Array }

ใช่ในฐานะพลเมือง TypeScript ที่ดีเราสร้างอินเทอร์เฟซสำหรับผลลัพธ์ GraphQL

เชิงมุม

@Injectable() export class PostsService { posts = [] constructor(private apollo: Apollo) { } initializePosts() { this.apollo.query({ query: PostsQuery, fetchPolicy: 'network-only' }).subscribe(({ data }) => { this.posts = data.allPosts }) } }

แบบสอบถาม GraphQL เป็น RxJS ที่สังเกตได้และเราสมัครรับข้อมูล มันใช้งานได้เหมือนคำสัญญา แต่ไม่มากดังนั้นเราจึงโชคไม่ดีที่ใช้ async/await แน่นอนว่ายังมี สัญญา แต่ดูเหมือนจะไม่ใช่วิธีเชิงมุมอยู่ดี เราตั้ง fetchPolicy: 'network-only' เนื่องจากในกรณีนี้เราไม่ต้องการแคชข้อมูล แต่จะดึงข้อมูลใหม่ทุกครั้ง

ตอบสนอง

export class PostsStore { appStore: AppStore @observable posts: Array = [] constructor() { this.appStore = AppStore.getInstance() } async initializePosts() { const result = await this.appStore.apolloClient.query({ query: PostsQuery, fetchPolicy: 'network-only' }) this.posts = result.data.allPosts } }

เวอร์ชัน React เกือบจะเหมือนกัน แต่เป็น apolloClient ที่นี่ใช้คำสัญญาเราสามารถใช้ประโยชน์จาก async/await ไวยากรณ์ มีวิธีการอื่น ๆ ในการตอบสนองที่เพียงแค่ 'เทป' การสอบถาม GraphQL ไป ส่วนประกอบลำดับที่สูงขึ้น แต่สำหรับฉันแล้วดูเหมือนว่าการผสมผสานข้อมูลและเลเยอร์การนำเสนอเข้าด้วยกันมากเกินไป

สรุป: แนวคิดของ RxJS subscribe vs. async / await นั้นค่อนข้างเหมือนกัน

GraphQL - การบันทึกข้อมูล

รหัสทั่วไป

อีกครั้งรหัสที่เกี่ยวข้องกับ GraphQL:

const AddPostMutation = gql` mutation AddPostMutation($name: String!, $title: String!, $message: String!) { createPost( name: $name, title: $title, message: $message ) { id } } `

วัตถุประสงค์ของการกลายพันธุ์คือการสร้างหรืออัปเดตเรกคอร์ด ดังนั้นจึงเป็นประโยชน์ที่จะประกาศตัวแปรบางตัวที่มีการกลายพันธุ์เนื่องจากเป็นวิธีการส่งผ่านข้อมูลไปยังตัวแปรนั้น ดังนั้นเราจึงมี name, title และ message ตัวแปรที่พิมพ์เป็น String ซึ่งเราต้องเติมทุกครั้งที่เราเรียกสิ่งนี้ว่าการกลายพันธุ์ createPost ฟังก์ชันอีกครั้งถูกกำหนดโดย Graphcool เราระบุว่า Post คีย์ของโมเดลจะมีค่าจากตัวแปรการกลายพันธุ์และเราต้องการเพียงแค่ id ของโพสต์ที่สร้างขึ้นใหม่เพื่อส่งกลับ

เชิงมุม

@Injectable() export class FormService { constructor( private apollo: Apollo, private router: Router, private appService: AppService ) { } addPost(value) { this.apollo.mutate({ mutation: AddPostMutation, variables: { name: this.appService.username, title: value.title, message: value.message } }).subscribe(({ data }) => { this.router.navigate(['/posts']) }, (error) => { console.log('there was an error sending the query', error) }) } }

เมื่อเรียก apollo.mutate เราจำเป็นต้องให้การกลายพันธุ์ที่เราเรียกและตัวแปรด้วย เราได้ผลลัพธ์ใน subscribe โทรกลับและใช้ฉีด router เพื่อกลับไปที่รายการโพสต์

ตอบสนอง

export class FormStore { constructor() { this.appStore = AppStore.getInstance() this.routerStore = RouterStore.getInstance() this.postFormState = new PostFormState() } submit = async () => { await this.postFormState.form.validate() if (this.postFormState.form.error) return const result = await this.appStore.apolloClient.mutate( { mutation: AddPostMutation, variables: { name: this.appStore.username, title: this.postFormState.title.value, message: this.postFormState.message.value } } ) this.goBack() } goBack = () => { this.routerStore.history.push('/posts') } }

คล้ายกับข้างต้นมากโดยมีความแตกต่างของการฉีดขึ้นต่อกันแบบ 'ด้วยตนเอง' และการใช้ async/await

สรุป: อีกครั้งไม่แตกต่างกันมากที่นี่ สมัครสมาชิกกับ async / await นั้นโดยพื้นฐานแล้วสิ่งที่แตกต่างกัน

แบบฟอร์ม

เราต้องการบรรลุเป้าหมายต่อไปนี้ด้วยแบบฟอร์มในแอปพลิเคชันนี้:

  • การผูกข้อมูลของเขตข้อมูลกับแบบจำลอง
  • ข้อความตรวจสอบความถูกต้องสำหรับแต่ละฟิลด์กฎหลายข้อ
  • รองรับการตรวจสอบว่าแบบฟอร์มทั้งหมดถูกต้องหรือไม่

ตอบสนอง

export const check = (validator, message, options) => (value) => (!validator(value, options) && message) export const checkRequired = (msg: string) => check(nonEmpty, msg) export class PostFormState { title = new FieldState('').validators( checkRequired('Title is required'), check(isLength, 'Title must be at least 4 characters long.', { min: 4 }), check(isLength, 'Title cannot be more than 24 characters long.', { max: 24 }), ) message = new FieldState('').validators( checkRequired('Message cannot be blank.'), check(isLength, 'Message is too short, minimum is 50 characters.', { min: 50 }), check(isLength, 'Message is too long, maximum is 1000 characters.', { max: 1000 }), ) form = new FormState({ title: this.title, message: this.message }) }

ดังนั้น formstate ไลบรารีทำงานดังนี้: สำหรับแต่ละฟิลด์ในฟอร์มของคุณคุณกำหนด a FieldState พารามิเตอร์ที่ส่งผ่านคือค่าเริ่มต้น validators คุณสมบัติรับฟังก์ชันซึ่งส่งคืน 'เท็จ' เมื่อค่าถูกต้องและข้อความตรวจสอบความถูกต้องเมื่อค่าไม่ถูกต้อง ด้วย check และ checkRequired ฟังก์ชั่นตัวช่วยทุกอย่างสามารถเปิดเผยได้อย่างสวยงาม

เพื่อให้มีการตรวจสอบความถูกต้องสำหรับทั้งแบบฟอร์มคุณควรรวมฟิลด์เหล่านั้นด้วย FormState อินสแตนซ์ซึ่งจะให้ความถูกต้องโดยรวม

@inject('appStore', 'formStore') @observer export class FormComponent extends React.Component { render() { const { appStore, formStore } = this.props const { postFormState } = formStore return

Create a new post

You are now posting as {appStore.username}

FormState อินสแตนซ์ให้ value, onChange และ error คุณสมบัติซึ่งสามารถใช้กับส่วนประกอบส่วนหน้าได้อย่างง่ายดาย

} }

เมื่อ form.hasError คือ true เราปิดการใช้งานปุ่มไว้ ปุ่มส่งจะส่งแบบฟอร์มไปยังการกลายพันธุ์ของ GraphQL ที่นำเสนอก่อนหน้านี้

เชิงมุม

ใน Angular เราจะใช้ FormService และ FormBuilder ซึ่งเป็นส่วนหนึ่งของ @angular/forms แพ็คเกจ

@Component({ selector: 'app-form', templateUrl: './form.component.html', providers: [ FormService ] }) export class FormComponent { postForm: FormGroup validationMessages = { 'title': { 'required': 'Title is required.', 'minlength': 'Title must be at least 4 characters long.', 'maxlength': 'Title cannot be more than 24 characters long.' }, 'message': { 'required': 'Message cannot be blank.', 'minlength': 'Message is too short, minimum is 50 characters', 'maxlength': 'Message is too long, maximum is 1000 characters' } }

ขั้นแรกให้กำหนดข้อความตรวจสอบความถูกต้อง

constructor( private router: Router, private formService: FormService, public appService: AppService, private fb: FormBuilder, ) { this.createForm() } createForm() { this.postForm = this.fb.group({ title: ['', [Validators.required, Validators.minLength(4), Validators.maxLength(24)] ], message: ['', [Validators.required, Validators.minLength(50), Validators.maxLength(1000)] ], }) }

การใช้ FormBuilder มันค่อนข้างง่ายในการสร้างโครงสร้างแบบฟอร์มและรวบรัดกว่าในตัวอย่าง React ด้วยซ้ำ

get validationErrors() { const errors = {} Object.keys(this.postForm.controls).forEach(key => { errors[key] = '' const control = this.postForm.controls[key] if (control && !control.valid) { const messages = this.validationMessages[key] Object.keys(control.errors).forEach(error => { errors[key] += messages[error] + ' ' }) } }) return errors }

ในการรับข้อความตรวจสอบความถูกต้องแบบผูกมัดเราจำเป็นต้องดำเนินการบางอย่าง รหัสนี้นำมาจากเอกสารอย่างเป็นทางการโดยมีการเปลี่ยนแปลงเล็กน้อย โดยทั่วไปใน FormService ฟิลด์จะอ้างอิงเฉพาะข้อผิดพลาดที่ใช้งานอยู่ซึ่งระบุโดยชื่อตัวตรวจสอบความถูกต้องดังนั้นเราจำเป็นต้องจับคู่ข้อความที่ต้องการด้วยตนเองกับฟิลด์ที่ได้รับผลกระทบ นี่ไม่ใช่ข้อเสียเปรียบทั้งหมด ตัวอย่างเช่นยืมตัวเองไปสู่ความเป็นสากลได้ง่ายขึ้น

onSubmit({ value, valid }) { if (!valid) { return } this.formService.addPost(value) } onCancel() { this.router.navigate(['/posts']) } }

อีกครั้งเมื่อฟอร์มถูกต้องสามารถส่งข้อมูลไปยังการกลายพันธุ์ของ GraphQL ได้

วิธีโค้ดหุ่นยนต์

Create a new post

You are now posting as {{appService.username}}

{{validationErrors['title']}}

{{validationErrors['message']}}

Cancel Submit

สิ่งที่สำคัญที่สุดคือการอ้างอิง formGroup ที่เราสร้างขึ้นด้วย FormBuilder ซึ่งก็คือ [formGroup]='postForm' มอบหมาย. เขตข้อมูลภายในฟอร์มถูกผูกไว้กับโมเดลฟอร์มผ่านทาง formControlName ทรัพย์สิน. อีกครั้งเราปิดการใช้งานปุ่ม 'ส่ง' เมื่อแบบฟอร์มไม่ถูกต้อง นอกจากนี้เรายังต้องเพิ่มการตรวจสอบความสกปรกเนื่องจากที่นี่รูปแบบที่ไม่สกปรกยังคงไม่ถูกต้อง เราต้องการให้สถานะเริ่มต้นของปุ่มเป็น 'เปิดใช้งาน'

สรุป: แนวทางในการทำแบบฟอร์มใน React และ Angular นี้ค่อนข้างแตกต่างกันทั้งในด้านการตรวจสอบความถูกต้องและเทมเพลต วิธีเชิงมุมเกี่ยวข้องกับ 'เวทมนตร์' มากกว่าเล็กน้อยแทนที่จะเป็นการผูกแบบตรงไปตรงมา แต่ในทางกลับกันจะสมบูรณ์และละเอียดกว่า

ขนาดมัด

อ้ออีกอย่าง การผลิตลดขนาดบันเดิล JS พร้อมการตั้งค่าเริ่มต้นจากตัวสร้างแอปพลิเคชัน: โดยเฉพาะอย่างยิ่ง Tree Shaking in React และการคอมไพล์ AOT ใน Angular

  • เชิงมุม: 1200 KB
  • ตอบสนอง: 300 KB

ไม่แปลกใจมากที่นี่ Angular เป็นสิ่งที่ใหญ่กว่าเสมอ

เมื่อใช้ gzip ขนาดจะลดลงเหลือ 275kb และ 127kb ตามลำดับ

โปรดทราบว่านี่คือไลบรารีของผู้ขายทั้งหมด จำนวนรหัสแอปพลิเคชันจริงมีเพียงเล็กน้อยเมื่อเปรียบเทียบซึ่งไม่ใช่ในกรณีของแอปพลิเคชันในโลกแห่งความเป็นจริง ที่นั่นอัตราส่วนน่าจะมากกว่า 1: 2 มากกว่า 1: 4 นอกจากนี้เมื่อคุณเริ่มรวมไลบรารีของบุคคลที่สามจำนวนมากด้วย React ขนาดของบันเดิลก็มีแนวโน้มที่จะเติบโตค่อนข้างเร็ว

ความยืดหยุ่นของไลบรารีเทียบกับความทนทานของกรอบงาน

ดูเหมือนว่าเราไม่สามารถ (อีกแล้ว!) ที่จะหาคำตอบที่ชัดเจนว่า Angular หรือ React นั้นดีกว่าสำหรับการพัฒนาเว็บ

ปรากฎว่าเวิร์กโฟลว์การพัฒนาใน React และ Angular อาจคล้ายกันมากขึ้นอยู่กับไลบรารีที่เราเลือกใช้ React ด้วย จากนั้นขึ้นอยู่กับความชอบส่วนบุคคลเป็นหลัก

หากคุณชอบสแต็คสำเร็จรูปการฉีดขึ้นรูปที่มีประสิทธิภาพและวางแผนที่จะใช้สินค้า RxJS บางอย่างให้เลือก Angular

หากคุณชอบคนจรจัดและสร้างสแต็กของคุณเองคุณชอบความตรงไปตรงมาของ JSX และชอบคุณสมบัติที่คำนวณได้ง่ายกว่าให้เลือก React / MobX

อีกครั้งคุณสามารถรับซอร์สโค้ดที่สมบูรณ์ของแอปพลิเคชันได้จากบทความนี้ ที่นี่ และ ที่นี่ .

หรือหากคุณต้องการที่ใหญ่กว่านี้ตัวอย่าง RealWorld:

  • RealWorld Angular 4+
  • RealWorld React / MobX

เลือกกระบวนทัศน์การเขียนโปรแกรมของคุณก่อน

การเขียนโปรแกรมด้วย React / MobX นั้นคล้ายกับ Angular มากกว่า React / Redux มีความแตกต่างที่น่าสังเกตในเทมเพลตและการจัดการการพึ่งพา แต่ก็มีเหมือนกัน ไม่แน่นอน / การผูกข้อมูล กระบวนทัศน์.

ตอบสนอง / Redux ด้วย ไม่เปลี่ยนรูป / ทิศทางเดียว กระบวนทัศน์เป็นสัตว์ร้ายที่แตกต่างกันอย่างสิ้นเชิง

อย่าหลงกลกับรอยเท้าเล็ก ๆ ของไลบรารี Redux อาจมีขนาดเล็ก แต่ก็เป็นกรอบ แนวทางปฏิบัติที่ดีที่สุดของ Redux ในปัจจุบันมุ่งเน้นไปที่การใช้ไลบรารีที่เข้ากันได้กับระบบ Redux เช่น Redux Saga สำหรับรหัส async และการดึงข้อมูล แบบฟอร์ม Redux สำหรับการจัดการแบบฟอร์ม เลือกใหม่ สำหรับตัวเลือกที่จำได้ (ค่าที่คำนวณของ Redux) และ จัดองค์ประกอบใหม่ เพื่อการจัดการวงจรชีวิตที่ละเอียดยิ่งขึ้น นอกจากนี้ยังมีการเปลี่ยนแปลงในชุมชน Redux จาก ไม่เปลี่ยนรูป js ถึง รามดา หรือ lodash / fp ซึ่งทำงานกับออบเจ็กต์ JS ธรรมดาแทนการแปลง

ตัวอย่างที่ดีของ Redux สมัยใหม่เป็นที่รู้จักกันดี React Boilerplate . มันเป็นกองพัฒนาที่น่ากลัว แต่ถ้าคุณดูมันมันแตกต่างจากที่เราเห็นในโพสต์นี้มากจริงๆ

ฉันรู้สึกว่า Angular ได้รับการปฏิบัติที่ไม่เป็นธรรมเล็กน้อยจากส่วนที่เป็นแกนนำของชุมชน JavaScript หลายคนที่แสดงความไม่พอใจกับเรื่องนี้อาจไม่พอใจกับการเปลี่ยนแปลงครั้งใหญ่ที่เกิดขึ้นระหว่าง AngularJS รุ่นเก่าและ Angular ในปัจจุบัน ในความคิดของฉันมันเป็นกรอบการทำงานที่สะอาดและมีประสิทธิผลมากที่จะพาโลกไปด้วยพายุหากเกิดขึ้นเมื่อ 1-2 ปีก่อนหน้านี้

อย่างไรก็ตาม Angular กำลังได้รับการตั้งหลักที่มั่นคงโดยเฉพาะอย่างยิ่งในโลกขององค์กรที่มีทีมงานขนาดใหญ่และความต้องการมาตรฐานและการสนับสนุนในระยะยาว หรือกล่าวอีกนัยหนึ่ง Angular เป็นวิธีที่วิศวกรของ Google คิดว่าการพัฒนาเว็บควรทำหากยังคงมีจำนวนมาก

สำหรับ MobX จะใช้การประเมินที่คล้ายกัน เยี่ยมมาก แต่ไม่ได้รับการชื่นชม

โดยสรุป: ก่อนที่จะเลือกระหว่าง React และ Angular ให้เลือกกระบวนทัศน์การเขียนโปรแกรมของคุณก่อน

ไม่แน่นอน / การผูกข้อมูล หรือ ไม่เปลี่ยนรูป / ทิศทางเดียว นั่น ... ดูเหมือนจะเป็นปัญหาที่แท้จริง

ทำความเข้าใจพื้นฐาน

React เป็นกรอบหรือไม่?

React เป็นไลบรารี JavaScript สำหรับสร้างส่วนต่อประสานผู้ใช้ เกี่ยวข้องกับมุมมองและช่วยให้คุณสามารถเลือกสถาปัตยกรรมส่วนหน้าที่เหลือของคุณได้ อย่างไรก็ตามระบบนิเวศของห้องสมุดที่แข็งแกร่งได้พัฒนาขึ้นรอบ ๆ ทำให้คุณสามารถสร้างเฟรมเวิร์กที่สมบูรณ์เกี่ยวกับ React ได้โดยการเพิ่มไลบรารีสองสามไลบรารีเข้าไป

ฉันจะใช้คุณสมบัติที่คำนวณใน Angular ได้อย่างไร

กำหนดค่าทั้งหมดที่ใช้เป็นพื้นฐานสำหรับคุณสมบัติที่คำนวณเป็น BehaviorSubject (พร้อมใช้งานผ่าน RxJS) และสมัครสมาชิกด้วยตนเองสำหรับแต่ละเรื่องที่คุณสมบัตินั้นขึ้นอยู่กับ

การเขียนโปรแกรมจำนวนเต็มผสม: คู่มือสำหรับการตัดสินใจเชิงคำนวณ

เทคโนโลยี

การเขียนโปรแกรมจำนวนเต็มผสม: คู่มือสำหรับการตัดสินใจเชิงคำนวณ
วิธีสร้างงบประมาณที่คงอยู่ตลอดทั้งปี

วิธีสร้างงบประมาณที่คงอยู่ตลอดทั้งปี

กระบวนการทางการเงิน

โพสต์ยอดนิยม
เอกสาร Agile: การปรับสมดุลความเร็วและการรักษาความรู้
เอกสาร Agile: การปรับสมดุลความเร็วและการรักษาความรู้
ทำลายหลักการออกแบบ (ด้วยอินโฟกราฟิก)
ทำลายหลักการออกแบบ (ด้วยอินโฟกราฟิก)
วิธีจัดโครงสร้างลำดับชั้นการพิมพ์ที่มีประสิทธิภาพ
วิธีจัดโครงสร้างลำดับชั้นการพิมพ์ที่มีประสิทธิภาพ
ฮาร์ดแวร์ที่คล่องตัวพร้อมการพัฒนาซอฟต์แวร์ในตัว
ฮาร์ดแวร์ที่คล่องตัวพร้อมการพัฒนาซอฟต์แวร์ในตัว
วิธีการรวม OAuth 2 เข้ากับ Django / DRF Back-end ของคุณโดยไม่บ้า
วิธีการรวม OAuth 2 เข้ากับ Django / DRF Back-end ของคุณโดยไม่บ้า
 
GWT Toolkit: สร้างส่วนหน้า JavaScript ที่มีประสิทธิภาพโดยใช้ Java
GWT Toolkit: สร้างส่วนหน้า JavaScript ที่มีประสิทธิภาพโดยใช้ Java
แหล่งข้อมูลสำหรับธุรกิจขนาดเล็กสำหรับ COVID-19: เงินกู้เงินช่วยเหลือและสินเชื่อ
แหล่งข้อมูลสำหรับธุรกิจขนาดเล็กสำหรับ COVID-19: เงินกู้เงินช่วยเหลือและสินเชื่อ
Libation Frontiers: เจาะลึกอุตสาหกรรมไวน์โลก
Libation Frontiers: เจาะลึกอุตสาหกรรมไวน์โลก
เรียนรู้ Markdown: เครื่องมือการเขียนสำหรับนักพัฒนาซอฟต์แวร์
เรียนรู้ Markdown: เครื่องมือการเขียนสำหรับนักพัฒนาซอฟต์แวร์
พบกับ Phoenix: กรอบงานคล้ายรางสำหรับเว็บแอปสมัยใหม่บน Elixir
พบกับ Phoenix: กรอบงานคล้ายรางสำหรับเว็บแอปสมัยใหม่บน Elixir
โพสต์ยอดนิยม
  • ตัวอย่างการออกแบบแอพมือถือที่ไม่ดี
  • การใช้ node.js . คืออะไร
  • ไม่มี api "undefined" หรือคุณไม่ได้รับอนุญาตให้เข้าถึง
  • วิธีสแปมบัตรเครดิต pdf
  • c ++ เมื่อใดควรใช้ใหม่
หมวดหมู่
  • ทีมแบบกระจาย
  • เคล็ดลับและเครื่องมือ
  • ชีวิตนักออกแบบ
  • นวัตกรรม
  • © 2022 | สงวนลิขสิทธิ์

    portaldacalheta.pt