คุณจะตัดสินใจอย่างไรคุณเลือกระหว่างสามสิ่งนี้อย่างไรโดยขึ้นอยู่กับวัตถุประสงค์ / ขนาด / อุปกรณ์ประกอบฉาก / พฤติกรรมของส่วนประกอบของเรา
การขยายจากReact.PureComponent
หรือจากReact.Component
ด้วยshouldComponentUpdate
วิธีการที่กำหนดเองจะมีผลกระทบด้านประสิทธิภาพ การใช้ส่วนประกอบการทำงานแบบไร้รัฐเป็นตัวเลือก "สถาปัตยกรรม" และไม่ได้รับประโยชน์ด้านประสิทธิภาพใด ๆ นอกกรอบ (ยัง)
สำหรับส่วนประกอบที่เรียบง่าย แต่เป็นการนำเสนอที่จำเป็นต้องนำกลับมาใช้ใหม่ได้ง่ายให้เลือกใช้ส่วนประกอบที่ใช้งานได้แบบไร้รัฐ วิธีนี้คุณมั่นใจได้ว่าพวกเขาจะแยกจากตรรกะแอปจริงที่พวกเขาเป็นเรื่องง่ายที่จะทดสอบและพวกเขาไม่ได้มีผลข้างเคียงที่ไม่คาดคิด ข้อยกเว้นคือถ้าด้วยเหตุผลบางอย่างคุณมีจำนวนมากหรือถ้าคุณต้องการวิธีการเรนเดอร์ที่ดีที่สุด (เนื่องจากคุณไม่สามารถกำหนดshouldComponentUpdate
องค์ประกอบการทำงานแบบไร้รัฐได้)
ขยายPureComponent
ถ้าคุณรู้ว่าการส่งออกของคุณขึ้นอยู่กับอุปกรณ์ประกอบฉาก / รัฐ ("ง่าย" หมายถึงไม่มีโครงสร้างข้อมูลที่ซ้อนกันเป็น PureComponent ทำการเปรียบเทียบตื้น) และคุณต้องการ / สามารถได้รับการปรับปรุงประสิทธิภาพ
ขยายComponent
และใช้งานของคุณเองshouldComponentUpdate
หากคุณต้องการประสิทธิภาพที่เพิ่มขึ้นโดยการเปรียบเทียบตรรกะที่กำหนดเองระหว่างอุปกรณ์ประกอบฉากถัดไป / ปัจจุบันและรัฐ ตัวอย่างเช่นคุณสามารถทำการเปรียบเทียบแบบลึกได้อย่างรวดเร็วโดยใช้ lodash # isEqual:
class MyComponent extends Component {
shouldComponentUpdate (nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
}
นอกจากนี้การใช้งานของคุณเองshouldComponentUpdate
หรือขยายจากPureComponent
นั้นเป็นการปรับให้เหมาะสมและตามปกติคุณควรเริ่มมองหาสิ่งนั้นเฉพาะเมื่อคุณมีปัญหาด้านประสิทธิภาพ ( หลีกเลี่ยงการปรับให้เหมาะสมก่อนเวลา ) ตามกฎทั่วไปฉันพยายามทำสิ่งที่ดีที่สุดเหล่านี้เสมอหลังจากที่แอปพลิเคชันอยู่ในสถานะใช้งานโดยคุณสมบัติส่วนใหญ่ได้นำไปใช้แล้ว มันง่ายมากที่จะมุ่งเน้นไปที่ปัญหาด้านประสิทธิภาพเมื่อพวกเขาเข้าใกล้
รายละเอียดเพิ่มเติม
ฟังก์ชั่นไร้สัญชาติ:
สิ่งเหล่านี้ถูกกำหนดโดยใช้ฟังก์ชั่น เนื่องจากไม่มีสถานะภายในสำหรับองค์ประกอบไร้สัญชาติเอาต์พุต (สิ่งที่แสดงผล) จะขึ้นอยู่กับอุปกรณ์ประกอบฉากที่กำหนดให้เป็นอินพุตสำหรับฟังก์ชันนี้
ข้อดี:
วิธีที่ง่ายที่สุดในการกำหนดส่วนประกอบใน React หากคุณไม่ต้องการจัดการสถานะใด ๆ ทำไมต้องกังวลกับคลาสและการสืบทอด หนึ่งในความแตกต่างที่สำคัญระหว่างฟังก์ชั่นและคลาสคือฟังก์ชั่นที่คุณมั่นใจว่าเอาต์พุตขึ้นอยู่กับอินพุตเท่านั้น (ไม่ได้อยู่ในประวัติของการประมวลผลก่อนหน้านี้)
ในอุดมคติของแอปคุณควรตั้งเป้าให้มีองค์ประกอบไร้สัญชาติมากที่สุดเท่าที่จะเป็นไปได้เพราะปกติแล้วหมายความว่าคุณย้ายตรรกะของคุณออกไปนอกเลเยอร์มุมมองและย้ายไปยังสิ่งอื่นเช่น Redux ซึ่งหมายความว่าคุณสามารถ (ทดสอบง่ายขึ้นนำมาใช้ใหม่ได้มากขึ้น ฯลฯ )
จุดด้อย:
ไม่มีวิธีวงจรชีวิต คุณไม่มีวิธีกำหนดcomponentDidMount
และเพื่อนคนอื่น ๆ โดยปกติคุณจะทำเช่นนั้นภายในองค์ประกอบหลักที่สูงขึ้นในลำดับชั้นเพื่อให้คุณสามารถเปลี่ยนเด็กทุกคนให้เป็นเด็กไร้สัญชาติ
ไม่มีวิธีการควบคุมด้วยตนเองเมื่อจำเป็นต้องทำการเรนเดอร์ซ้ำเนื่องจากคุณไม่สามารถกำหนดshouldComponentUpdate
ได้ การเรนเดอร์เกิดขึ้นทุกครั้งที่ส่วนประกอบได้รับอุปกรณ์ประกอบฉากใหม่ (ไม่มีทางเปรียบเทียบอย่างตื้นเขิน ฯลฯ ) ในอนาคต React สามารถปรับองค์ประกอบไร้สัญชาติให้เหมาะสมโดยอัตโนมัติตอนนี้มีห้องสมุดบางส่วนที่คุณสามารถใช้ได้ เนื่องจากส่วนประกอบไร้สัญชาติเป็นเพียงฟังก์ชั่นโดยทั่วไปเป็นปัญหาคลาสสิกของ "การบันทึกฟังก์ชัน"
ไม่รองรับการอ้างอิง: https://github.com/facebook/react/issues/4936
คอมโพเนนต์ที่ขยายคลาส PureComponent VS คอมโพเนนต์ปกติที่ขยายคลาสคอมโพเนนต์:
ตอบสนองเคยมีPureRenderMixin
คุณสามารถแนบกับคลาสที่กำหนดโดยใช้React.createClass
ไวยากรณ์ มิกซ์อินจะshouldComponentUpdate
ทำการเปรียบเทียบตื้น ๆ ระหว่างอุปกรณ์ประกอบฉากถัดไปกับรัฐถัดไปเพื่อตรวจสอบว่ามีอะไรเปลี่ยนแปลงหรือไม่ หากไม่มีอะไรเปลี่ยนแปลงก็ไม่จำเป็นต้องทำการเรนเดอร์ซ้ำอีกครั้ง
หากคุณต้องการใช้ไวยากรณ์ ES6 คุณไม่สามารถใช้มิกซ์อินได้ ดังนั้นเพื่อความสะดวก React แนะนำระดับที่คุณสามารถรับมรดกจากแทนการใช้PureComponent
เพียงแค่การดำเนินการในลักษณะเดียวกันของ มันเป็นสิ่งอำนวยความสะดวกส่วนใหญ่คุณจึงไม่ต้องใช้มันด้วยตัวเองเนื่องจากการเปรียบเทียบระหว่างสถานะปัจจุบัน / ถัดไปที่ตื้นและอุปกรณ์ประกอบฉากน่าจะเป็นสถานการณ์ที่พบบ่อยที่สุดที่สามารถให้ประสิทธิภาพที่รวดเร็วแก่คุณได้Component
PureComponent
shouldComponentUpdate
PureRendererMixin
ตัวอย่าง:
class UserAvatar extends Component {
render() {
return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
}
}
ขณะที่คุณสามารถเห็นผลลัพธ์ขึ้นอยู่กับและprops.imageUrl
props.username
หากอยู่ในองค์ประกอบหลักที่คุณแสดง<UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" />
ด้วยอุปกรณ์ประกอบฉากเดียวกัน React จะเรียกrender
ทุกครั้งแม้ว่าเอาต์พุตจะเหมือนกันทุกประการ โปรดจำไว้ว่าแม้ว่า React จะสร้างความแตกต่างดังนั้น DOM จะไม่ได้รับการอัปเดตจริง ๆ กระนั้นการแสดงความแตกต่างของโดมอาจมีราคาแพงดังนั้นในสถานการณ์นี้มันจะเป็นการสิ้นเปลือง
หากUserAvatar
องค์ประกอบขยายออกไปPureComponent
จะทำการเปรียบเทียบแบบตื้น และเนื่องจากอุปกรณ์ประกอบฉากและอุปกรณ์ต่อไปเหมือนกันrender
จะไม่ถูกเรียกเลย
หมายเหตุเกี่ยวกับคำจำกัดความของ "บริสุทธิ์" ใน React:
โดยทั่วไป "ฟังก์ชั่นบริสุทธิ์" เป็นฟังก์ชั่นที่ประเมินผลเสมอเพื่อให้ได้ผลลัพธ์เดียวกันที่ได้รับการป้อนข้อมูลเดียวกัน ผลลัพธ์ (สำหรับ React นั่นคือสิ่งที่ถูกส่งคืนโดยrender
วิธีการ) ไม่ได้ขึ้นอยู่กับประวัติ / รัฐใด ๆ และไม่มีผลข้างเคียงใด ๆ (การดำเนินการที่เปลี่ยน "โลก" นอกฟังก์ชั่น)
ในการตอบสนอง, ส่วนประกอบไร้สัญชาติไม่จำเป็นต้องมีส่วนประกอบที่บริสุทธิ์ตามนิยามข้างต้นถ้าคุณเรียกว่า "ไร้สัญชาติ" องค์ประกอบที่ไม่เคยเรียกร้องที่และที่ไม่ได้ใช้this.setState
this.state
ในความเป็นจริงใน a PureComponent
คุณยังคงสามารถทำผลข้างเคียงได้ในระหว่างวงจรชีวิต ตัวอย่างเช่นคุณสามารถส่งคำขอภายในอาแจ็กซ์componentDidMount
หรือคุณอาจจะทำการคำนวณ DOM บางแบบไดนามิกปรับความสูงของ div render
ภายใน
คำจำกัดความ "องค์ประกอบโง่" มีความหมาย "ปฏิบัติ" มากกว่า (อย่างน้อยในความเข้าใจของฉัน): องค์ประกอบโง่ "ได้รับการบอก" สิ่งที่ต้องทำโดยองค์ประกอบแม่ผ่านอุปกรณ์ประกอบฉากและไม่รู้วิธีการทำสิ่งต่าง ๆ แต่ใช้อุปกรณ์ประกอบฉาก โทรกลับแทน
ตัวอย่างของ "สมาร์ท" AvatarComponent
:
class AvatarComponent extends Component {
expandAvatar () {
this.setState({ loading: true });
sendAjaxRequest(...).then(() => {
this.setState({ loading: false });
});
}
render () {
<div onClick={this.expandAvatar}>
<img src={this.props.username} />
</div>
}
}
ตัวอย่างของ "ใบ้" AvatarComponent
:
class AvatarComponent extends Component {
render () {
<div onClick={this.props.onExpandAvatar}>
{this.props.loading && <div className="spinner" />}
<img src={this.props.username} />
</div>
}
}
ในที่สุดฉันจะบอกว่า "โง่", "ไร้สัญชาติ" และ "บริสุทธิ์" เป็นแนวคิดที่แตกต่างกันมากซึ่งบางครั้งอาจทับซ้อนกัน แต่ไม่จำเป็นขึ้นอยู่กับกรณีการใช้งานของคุณเป็นส่วนใหญ่