คุณจะตัดสินใจอย่างไรคุณเลือกระหว่างสามสิ่งนี้อย่างไรโดยขึ้นอยู่กับวัตถุประสงค์ / ขนาด / อุปกรณ์ประกอบฉาก / พฤติกรรมของส่วนประกอบของเรา
การขยายจาก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 เพียงแค่การดำเนินการในลักษณะเดียวกันของ มันเป็นสิ่งอำนวยความสะดวกส่วนใหญ่คุณจึงไม่ต้องใช้มันด้วยตัวเองเนื่องจากการเปรียบเทียบระหว่างสถานะปัจจุบัน / ถัดไปที่ตื้นและอุปกรณ์ประกอบฉากน่าจะเป็นสถานการณ์ที่พบบ่อยที่สุดที่สามารถให้ประสิทธิภาพที่รวดเร็วแก่คุณได้ComponentPureComponentshouldComponentUpdatePureRendererMixin
ตัวอย่าง:
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.setStatethis.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>
}
}
ในที่สุดฉันจะบอกว่า "โง่", "ไร้สัญชาติ" และ "บริสุทธิ์" เป็นแนวคิดที่แตกต่างกันมากซึ่งบางครั้งอาจทับซ้อนกัน แต่ไม่จำเป็นขึ้นอยู่กับกรณีการใช้งานของคุณเป็นส่วนใหญ่