หนึ่งในปัญหาที่ใหญ่ที่สุดและพบบ่อยที่สุดใน การพัฒนาเว็บส่วนหน้า คือการจัดการของรัฐ นักพัฒนาส่วนหน้าอิสระ เช่นฉันมุ่งเน้นไปที่การทำให้ออบเจ็กต์สถานะซิงค์กับมุมมองและการแสดง DOM อย่างต่อเนื่อง ผู้ใช้สามารถโต้ตอบกับแอปพลิเคชันได้หลายวิธีและเป็นงานใหญ่ที่ต้องเปลี่ยนจากสถานะหนึ่งไปสู่อีกสถานะหนึ่ง
เมื่อไม่นานมานี้เว็บแอปพลิเคชันมีการไหลของข้อมูลที่ง่ายกว่ามาก เบราว์เซอร์จะส่งคำขอไปยังเซิร์ฟเวอร์ตรรกะของแอปพลิเคชันทั้งหมดจะดำเนินการบนเซิร์ฟเวอร์และมุมมอง HTML แบบเต็มจะถูกส่งกลับไปยังเบราว์เซอร์เพื่อนำเสนอให้กับผู้ใช้ การดำเนินการของผู้ใช้ในภายหลัง (เช่นการคลิกการส่งแบบฟอร์ม ฯลฯ ) จะทริกเกอร์ขั้นตอนเดียวกันอีกครั้ง แอปพลิเคชันไม่ต้องกังวลเกี่ยวกับสถานะของผู้ใช้และแต่ละมุมมองสามารถสร้างใหม่ได้โดยการส่งคำขอใหม่ไปยังเซิร์ฟเวอร์
อย่างไรก็ตามเว็บแอปพลิเคชัน เติบโตขึ้นในความซับซ้อนของพวกเขา และความต้องการของผู้ใช้ UI / UX ก็ก้าวหน้าเช่นกัน การโหลดซ้ำทั้งหน้าเมื่อมีการเปลี่ยนแปลงเพียงส่วนเดียวไม่ได้ผลและช้า เราต้องการการโต้ตอบที่รวดเร็วรวดเร็วและตอบสนองโดยมีผลกระทบต่อ UI ในทันที
JavaScript เข้ามาช่วย นักพัฒนาเริ่มเขียนโค้ดจำนวนมากที่ดำเนินการในเบราว์เซอร์ก่อนที่จะส่งคำขอไปยังเซิร์ฟเวอร์ jQuery ยังนำความก้าวหน้าที่สำคัญมาสู่การพัฒนาเว็บส่วนหน้าเนื่องจากมีความสามารถนอกกรอบที่เรียบง่ายและมีประสิทธิภาพเช่นการตรวจสอบฝั่งไคลเอ็นต์หน้าต่างโมดอลข้อความแจ้งเตือนภาพเคลื่อนไหวและแม้แต่การอัปเดตหน้าบางส่วนที่ใช้ Ajax
มาดูตัวอย่างง่ายๆในการประเมินความปลอดภัยของรหัสผ่าน หากรหัสผ่านตกลงช่องป้อนข้อมูลควรมีขอบสีเขียวและควรแสดงข้อความที่ดี หากรหัสผ่านอ่อนแอช่องป้อนข้อมูลควรมีขอบสีแดงและควรแสดงข้อความเตือน นอกจากนี้เรายังอาจแสดงใบหน้าที่ยิ้มเมื่อรหัสผ่านมีความรัดกุมเพียงพอ
โค้ดต่อไปนี้แสดงให้เห็นว่าการจัดการ DOM ทำได้อย่างไร ที่นี่มี“ ifs” จำนวนมากและโค้ดก็อ่านได้ไม่ยาก
if (hasInputBorder()) { removeInputBorder(); } if (text.length === 0) { if (hasMessage()) { removeMessage(); } if (hasSmiley()) { removeSmiley(); } } else { var strength = getPasswordStrength(text); if (!hasInputBorder()) { addInputBorder(); } var color = (strength == 'weak' ? 'red' : 'green'); setInputBorderColor(color); var message = (strength == 'weak' ? 'Password is weak' : 'That's what I call a password!'); if (hasMessage()) { setMessageText(message); } else { addMessageWithText(message); } if (strength == 'weak') { if (hasSmiley()) { removeSmiley(); } } else { if (!hasSmiley()) { addSmiley(); } } }
ดังที่แสดงไว้ด้านบนก่อนอื่นเราต้องตรวจสอบว่าผู้ใช้ระบุรหัสผ่านหรือไม่และจัดการกรณีที่ช่องรหัสผ่านว่างเปล่า และในทุกกรณีเราต้องตรวจสอบให้แน่ใจว่าองค์ประกอบ DOM ที่เกี่ยวข้องทั้งหมดได้รับการอัปเดตอย่างเหมาะสม ซึ่งรวมถึงข้อความเส้นขอบและใบหน้าที่ยิ้ม
ฟิลด์รหัสผ่านของเราสามารถอยู่ในสถานะหนึ่งในสามสถานะ: ว่างเปล่าอ่อนแอหรือแข็งแกร่ง และตามที่ระบุไว้เรามีองค์ประกอบ DOM สามแบบที่แตกต่างกันซึ่งได้รับผลกระทบจากสถานะฟิลด์รหัสผ่าน การจัดการชุดค่าผสมทั้งหมดและตรวจสอบให้แน่ใจว่ามุมมองของเราแสดงอย่างถูกต้องจะเพิ่มขึ้น ความซับซ้อนของวัฏจักร สำหรับโค้ดง่ายๆเช่นนี้
DOM ทำงานในไฟล์ โหมดเก็บรักษา ซึ่งหมายความว่าจะจำสถานะปัจจุบันเท่านั้น ในการแก้ไขมุมมองของเราเราจำเป็นต้องให้คำแนะนำสำหรับองค์ประกอบ DOM แต่ละรายการและตั้งโปรแกรมการเปลี่ยนแปลง
การเปลี่ยนการเข้ารหัสแทนสถานะอาจมีความซับซ้อน จำนวนสาขาและการตรวจสอบที่เราต้องดำเนินการในโค้ดของเราเพิ่มขึ้นอย่างทวีคูณพร้อมกับจำนวนสถานะมุมมองที่ต้องจัดการ
ในตัวอย่างของเราเรากำหนดสถานะมุมมองสามแบบซึ่งทำให้เรา 3 * 2 = 6
การเปลี่ยน โดยทั่วไปเมื่อกำหนด N รัฐเรามี N * (N - 1) = N^2 - N
การเปลี่ยนภาพที่เราต้องสร้างแบบจำลอง ลองนึกถึงความซับซ้อนที่เพิ่มขึ้นหากเราเพิ่มสถานะที่สี่ลงในตัวอย่างของเรา
โดยทั่วไปจะมีรหัสที่เกี่ยวข้องกับการสร้างแบบจำลองไฟล์ การเปลี่ยน . จะดีกว่ามากถ้าเราสามารถกำหนดสถานะมุมมองของเราได้และไม่ต้องกังวลกับรายละเอียดทั้งหมดของการเปลี่ยนจากสถานะหนึ่งไปเป็นอีกสถานะหนึ่ง
สมมติว่าเราทำได้ ประกาศ สถานะมุมมองขึ้นอยู่กับสถานะแบบจำลองแทนที่จะเป็น อย่างชัดเจน การเข้ารหัสการเปลี่ยนจากสถานะหนึ่งไปเป็นอีกสถานะหนึ่งเราอาจมีสิ่งนี้:
var strength = getPasswordStrength(text); if (text.length == 0) { return div(input({type: 'password', value: text})); } else if (strength == 'weak') { return div( input({type: 'password', value: text, borderColor: 'red'}), span({}, 'Weak') ); } else { return div( input({type: 'password', value: text, borderColor: 'green'}), span({}, 'That's what I call a password!'), img({class: 'icon-smiley'}) ); }
ที่นี่เรามีโค้ดง่ายๆสามสาขาซึ่งแสดงสถานะที่เป็นไปได้สามอย่างของแอพของเรา เราเพียงแค่ส่งคืนข้อกำหนดของมุมมองในแต่ละสาขาขึ้นอยู่กับสถานะของโมเดล รหัสการจัดการ DOM ทั้งหมดจะถูกลบออก เราเพียงแค่ให้ข้อมูลเกี่ยวกับ อะไร เราต้องการไม่ใช่ อย่างไร เพื่อไปที่นั่น
แม้ว่าวิธีนี้จะช่วยลดความซับซ้อนของโค้ดลงได้มาก แต่ก็ถือว่ามีใครบางคนหรืออย่างอื่นที่จะดูแลการจัดการ DOM จริงในนามของเรา
นี่คือที่ ตอบสนอง เข้ามาการตอบสนองจะทำให้แน่ใจว่าสถานะมุมมองได้รับการจัดการและอัปเดตทันทีตามสถานะของโมเดลข้อมูลที่อยู่เบื้องหลัง
React เป็นไลบรารี JavaScript ที่สร้างโดย Facebook ออกแบบมาเพื่อจัดการกับส่วน UI ของเว็บแอปพลิเคชัน คุณสามารถคิดว่ามันเป็นสถาปัตยกรรม V ใน MVC มันเน้นมาก ไม่มีการตั้งสมมติฐานเกี่ยวกับสแต็กเทคโนโลยีที่เหลือของคุณและไม่ได้จัดการสิ่งอื่นใดนอกจากการแสดงผลส่วนประกอบ ไม่มีกลไกการกำหนดเส้นทางโมเดลหรือคุณสมบัติอื่น ๆ ที่มักจะรวมอยู่ในเฟรมเวิร์กขนาดใหญ่ ดังนั้นคุณสามารถผสมและใช้กับไลบรารีหรือกรอบงานอื่น ๆ ที่คุณต้องการได้
React ช่วยให้เรากำหนด UIs เป็นโครงสร้างของส่วนประกอบคอมโพสิต ก ตอบสนองผู้พัฒนา กำหนดส่วนประกอบเหล่านั้นโดยระบุก ฟังก์ชันการแสดงผล ที่อธิบายส่วนประกอบโดยระบุสถานะอินพุต ฟังก์ชันนั้นควรจะเป็น บริสุทธิ์ (กล่าวคือไม่ควรมีผลข้างเคียงใด ๆ หรือขึ้นอยู่กับสิ่งอื่นนอกเหนือจากการป้อนข้อมูลที่ชัดเจน)
ฟังก์ชัน render จะส่งกลับคำอธิบายมุมมองซึ่ง React เรียกว่า a DOM เสมือน . คิดว่าเป็นวัตถุ JavaScript ที่สอดคล้องกับองค์ประกอบ DOM ที่แสดงผล
เมื่อคุณเปลี่ยนสถานะของคอมโพเนนต์ก็จะแสดงผลตัวเองและองค์ประกอบย่อยทั้งหมดอีกครั้งโดยส่งคืนใหม่ DOM เสมือน .
ยิ่งไปกว่านั้น React จะไม่ทำการแทนที่ HTML ง่ายๆเมื่อเปลี่ยนจากสถานะหนึ่งไปเป็นอีกสถานะหนึ่ง จะพบความแตกต่างระหว่างสถานะก่อนหน้าและสถานะใหม่และคำนวณชุดการดำเนินการ DOM ที่มีประสิทธิภาพสูงสุดเพื่อดำเนินการเปลี่ยน
แม้ว่าจะไม่คำนึงถึงประสิทธิภาพการทำงาน แต่การลดความซับซ้อนของโค้ดก็มีความสำคัญและช่วยให้เราสามารถมุ่งเน้นไปที่ส่วนที่เป็นเอกลักษณ์และซับซ้อนมากขึ้นของแอปพลิเคชันของเรา
เพื่อให้เป็นรูปธรรมมากขึ้นนี่คือตัวอย่างการสอนของเราโดยใช้ React เพื่อจัดการสถานะมุมมอง
หมายเหตุ: ตัวอย่างโค้ดต่อไปนี้เขียนในรูปแบบ JSX ตัวประมวลผลล่วงหน้าซึ่งเป็นวิธีทั่วไปในการเขียน UI ที่ใช้ปฏิกิริยา
function getPasswordStrength(text) { // Some code that calculates the strength given the password text. } var PasswordWithStrength = React.createClass({ getInitialState: function() { return {value: ''}; }, render: function() { var strength = getPasswordStrength(this.state.value); if (this.state.value.length == 0) { return ; } else if (strength == 'weak') { return Weak! ; } else { return That's what I call a password! ; } }, handleInputChange: function(ev) { this.setState({value: ev.target.value}); } }); React.render(, document.body);
Emoji
คอมโพเนนต์ที่แสดงผลเมื่อความปลอดภัยของรหัสผ่านใช้ได้เป็นเพียงส่วนประกอบที่กำหนดเองอื่น (เช่นเดียวกับ PasswordWithStrength
) กำหนดไว้ดังนี้:
var Emoji = React.createClass({ render: function() { var emojiSrc = this.props.value + '.png'; return ; } });
อย่างไรก็ตามในความเป็นธรรมมีเฟรมเวิร์ก JavaScript ฝั่งไคลเอ็นต์อื่น ๆ (เช่น Ember, Angular, Knockout และอื่น ๆ ) ที่แก้ปัญหาการจัดการสถานะมุมมองได้เช่นกันและยังเพิ่มคุณสมบัติอื่น ๆ ให้อีกด้วย เหตุใดคุณจึงต้องการใช้ React แทนกรอบงานอื่น ๆ ?
มีข้อดีที่สำคัญสองประการที่ React มีเมื่อเทียบกับไลบรารีอื่น ๆ ส่วนใหญ่
เฟรมเวิร์กทางเลือกอื่น ๆ บางส่วนใช้การผูกข้อมูลเพื่อแมปองค์ประกอบ DOM กับคุณสมบัติของรัฐและทำให้พวกเขาซิงค์กันโดยสังเกตการเปลี่ยนแปลงคุณสมบัติ วิธีนี้ช่วยให้สามารถแสดงผลมุมมองได้ครั้งเดียวโดยการเปลี่ยนแปลงแต่ละครั้งจะทริกเกอร์เฉพาะการแก้ไของค์ประกอบ DOM ที่ได้รับผลกระทบ ใช้ทางเลือกอื่น การตรวจสอบสกปรก ; นั่นคือแทนที่จะสังเกตการเปลี่ยนแปลงคุณสมบัติแต่ละรายการพวกเขาเพียงแค่ทำการแตกต่างระหว่างสถานะก่อนหน้ากับสถานะใหม่ ปฏิกิริยาจะคล้ายกับวิธีการหลังมากกว่า แต่แทนที่จะเปรียบเทียบสถานะจะเปรียบเทียบการแสดงมุมมอง
React ไม่มีการผูกข้อมูล คาดว่านักพัฒนาจะเรียกว่า setState
วิธีการหรือการแสดงผลองค์ประกอบด้านบนอีกครั้งเมื่อสถานะมีการเปลี่ยนแปลง มันรวบรวมการไหลแบบทิศทางเดียวจากสถานะไปสู่มุมมอง
แนวคิดนี้ง่ายต่อการนำไปใช้เนื่องจากนักพัฒนาโดยทั่วไปไม่คิดเกี่ยวกับการผูกข้อมูล โฟกัสอยู่ที่การแสดงภาพของข้อมูล คุณจึงไม่จำเป็นต้องคิดเกี่ยวกับคุณสมบัติที่ขึ้นต่อกันการจัดรูปแบบการผูกแท็ก HTML พิเศษ ฯลฯ ด้วย React คุณเพียงแค่แสดงองค์ประกอบอีกครั้งเมื่อโมเดลเปลี่ยนไป
ข้อใดต่อไปนี้ไม่ใช่วิธีที่จะช่วยให้คุณเข้าใจขอบเขตที่ใหญ่ขึ้นของเวิร์กโฟลว์
เพื่อทำความเข้าใจความแตกต่างในมุมมองการจัดการของรัฐที่นี่ ลองเปรียบเทียบ Ember กับ React . เราจะสร้างวัตถุ person
ที่จะแสดงชื่อเต็มเป็นตัวพิมพ์ใหญ่ หลังจากผ่านไปสองวินาทีเราจะจำลองการเปลี่ยนแปลงและอัปเดตมุมมอง
// EXAMPLE USING EMBER App = Ember.Application.create(); App.Person = Ember.Object.extend({ firstName: null, lastName: null, fullName: function() { return this.get('firstName') + ' ' + this.get('lastName'); }.property('firstName', 'lastName') }); var person = App.Person.create({ firstName: 'John', lastName: 'Doe' }); Ember.Handlebars.helper('upcase', function(value) { return value.toUpperCase(); }); App.IndexRoute = Ember.Route.extend({ model: function () { return person; } }); setTimeout(function() { person.set('firstName', 'Harry'); }, 2000); // Templates: Welcome to Ember.js
{{outlet}} The current user is: {{upcase model.fullName}}
เราสร้างวัตถุด้วย firstName
, lastName
และ fullName
คุณสมบัติ. เนื่องจาก Ember กำลังสังเกตการเปลี่ยนแปลงคุณสมบัติเราจึงต้องระบุว่า fullName
ขึ้นอยู่กับ firstName
และ lastName
. ในการดำเนินการนี้เราได้เพิ่ม .property('firstName', 'lastName')
เมื่อเรากำหนด fullName
หลังจากนั้นสองวินาที person.set('firstName', 'Harry');
ถูกดำเนินการ สิ่งนี้ทำให้เกิดการอัปเดตมุมมองและการเชื่อมโยง
ตอนนี้เรามาทำแบบเดียวกันใน React
// EXAMPLE USING REACT var CurrentUser = React.createClass({ render: function() { return The current user is: {this.props.user.fullName().toUpperCase()} ; } }); var person = { firstName: 'John', lastName: 'Doe', fullName: function() { return this.firstName + ' ' + this.lastName; } }; var currentUser = React.render(, document.body); setTimeout(function() { person.firstName = 'Harry'; currentUser.setProps({user: person}); }, 2000);
แม้ว่าโค้ด Ember จะง่ายและอ่านง่าย แต่ก็เห็นได้ชัดว่า React ชนะในความเรียบง่าย person
เป็นวัตถุ JavaScript ธรรมดาที่มี fullName
เป็นเพียงฟังก์ชัน
กรอบงานทางเลือกแต่ละรายการมีวิธีจัดการเทมเพลตที่แตกต่างกัน บางคนใช้สตริงที่คอมไพล์เป็น JavaScript ในขณะที่คนอื่นใช้องค์ประกอบ DOM โดยตรง ส่วนใหญ่ใช้แอตทริบิวต์และแท็ก HTML ที่กำหนดเองซึ่งจะ 'รวบรวม' เป็น HTML
เทมเพลตไม่ได้เป็นส่วนหนึ่งของโค้ด JavaScript ด้วยเหตุนี้แต่ละทางเลือก ความต้องการ วิธีที่กำหนดเองเพื่อแสดงถึงการดำเนินการทั่วไปเงื่อนไขการทำซ้ำฟังก์ชันการโทร ฯลฯ ทั้งหมดนี้จบลงด้วยการสร้างภาษาหลอกใหม่ที่นักพัฒนาต้องเรียนรู้
ไม่มีเทมเพลตใน React ทุกอย่างเป็นเพียง JavaScript แบบเก่าเท่านั้น
React ใช้ JavaScript เต็มประสิทธิภาพเพื่อสร้างมุมมอง วิธีการแสดงผลของคอมโพเนนต์คือฟังก์ชัน JavaScript
JSX มีให้ใช้งานเป็นตัวประมวลผลก่อนที่จะเปลี่ยน“ ไวยากรณ์ที่เหมือน HTML” เป็น JavaScript ปกติ แต่ JSX เป็นทางเลือกและคุณมีอิสระที่จะใช้ JavaScript มาตรฐานโดยไม่ต้องมีตัวประมวลผลล่วงหน้า คุณยังสามารถใช้ประโยชน์จากเครื่องมือ JavaScript ที่มีอยู่ Linters, preprocessors, type annotations, minification, dead code removal ฯลฯ
เรามาใช้ตัวอย่างที่เป็นรูปธรรมอีกครั้งเพื่อเปรียบเทียบ React กับกรอบทางเลือกหนึ่งสำหรับการดูการจัดการสถานะ
บทช่วยสอนต่อไปนี้เป็นตัวอย่างการใช้ AngularJS เพื่อแสดงรายการแฮชแท็กและจำนวนทวีตสำหรับแต่ละรายการ รายการจะเรียงตามจำนวนและข้อความจะปรากฏขึ้นหากไม่มีแฮชแท็ก
- {{hashTag.name}} - {{hashTag.tweetCount}} tweets
No hashtags found!
เพื่อให้สามารถสร้างรายการนี้ได้นักพัฒนาต้องเรียนรู้เกี่ยวกับ AngularJS directives
, ng-show
และ ng-repeat
. จากนั้นเขาต้องเรียนรู้เกี่ยวกับ AngularJS filters
เข้าใจ orderBy
. งานง่าย ๆ อย่างการออกรายการ!
ตอนนี้เรามาพิจารณาตัวอย่างการตอบสนองที่ทำสิ่งเดียวกัน:
// EXAMPLE USING REACT function byTweetCountDesc(h1, h2) { return h2.tweetCount - h1.tweetCount; } //... render: function() { if (this.state.hashTags.length > 0) { var comps = this.state.hashTags.sort(byTweetCountDesc).map(function(hashTag, index) { return {hashTag.name} - {hashTag.tweetCount} tweets ; }); return {comps}
; } else { return No hashtags found! } }
แม้ว่าเราจะใช้วิธีการ 'ขั้นสูงกว่า' และ JSX นักพัฒนาเว็บทุกคนที่มีความเข้าใจพื้นฐานเกี่ยวกับ JavaScript ก็สามารถอ่านโค้ดด้านบนและเข้าใจสิ่งที่มันทำ การตรวจสอบเงื่อนไขมาตรฐานโดยใช้ if
, การทำซ้ำโดยใช้ map()
และ 'sort ()' มาตรฐานจะเกิดขึ้นกับนักพัฒนาซอฟต์แวร์ทุกคนดังนั้นจึงไม่มีไวยากรณ์เพิ่มเติมหรือแนวคิดอื่น ๆ ให้เรียนรู้
ประเด็นหลักจากบทช่วยสอน React.js นี้คือความจริงที่ว่า React ช่วยให้คุณสามารถมุ่งเน้นไปที่การจัดการสถานะมุมมองจริงมากกว่าช่วงการเปลี่ยนภาพซึ่งจะทำให้งานและแอปพลิเคชันของคุณง่ายขึ้น
เส้นโค้งการเรียนรู้สำหรับการนำ React มาใช้นั้นค่อนข้างไม่สำคัญ ไม่มีภาษาเทมเพลตที่กำหนดเองให้เชี่ยวชาญไม่มีการผูกข้อมูลให้ต้องกังวลและทุกอย่างจะรวมอยู่ในฟังก์ชัน JavaScript ที่อธิบายองค์ประกอบ UI
หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับการทำให้รหัสแอปพลิเคชันของคุณง่ายขึ้นโดยใช้ React โปรดดูคำพูดนี้โดย Steven Luscher รหัสที่ซับซ้อนด้วยการตอบสนอง .
นี่คือการอ่านเพิ่มเติมสำหรับทุกคนที่ต้องการก้าวไปอีกขั้นและเริ่มใช้ React: