React中控制子組件顯示隱藏的兩種方式及對比詳解
方式一:子組件觸發(fā)函數(shù)修改父組件狀態(tài)
先來看一段代碼:
// 父組件 import React, { useState } from 'react'; import Modal from './Modal'; const ParentComponent = () => { const [isModalVisible, setIsModalVisible] = useState(false); const handleOpenModal = () => { setIsModalVisible(true); }; const handleCloseModal = () => { setIsModalVisible(false); }; return ( <div> <button onClick={handleOpenModal}>打開模態(tài)框</button> {isModalVisible && <Modal onClose={handleCloseModal} />} </div> ); }; export default ParentComponent; // 子組件 import React from 'react'; const Modal = ({ onClose }) => { return ( <div className="modal"> <p>這是一個(gè)模態(tài)框</p> <button onClick={onClose}>關(guān)閉模態(tài)框</button> </div> ); }; export default Modal;
在這段代碼中,父組件來維護(hù)狀態(tài) isModalVisible,當(dāng)子組件通過調(diào)用onClose 時(shí)來設(shè)置 isModalVisible為true/false。從而實(shí)現(xiàn)子組件的顯示或者隱藏。
優(yōu)點(diǎn):
每次重新銷毀組件重建直接通過isModalVisible && <Modal/>
控制組件掛載/卸載。對于需要每次展示都重置內(nèi)部狀態(tài)(如表單)的彈窗,這種銷毀重建的方式更符合預(yù)期。
痛點(diǎn):
每次子組件觸發(fā)onClose
時(shí),父組件的狀態(tài)(isModalVisible)都會(huì)變化,進(jìn)而導(dǎo)致父組件及其所有子組件重新渲染。即使這個(gè)彈窗的顯隱邏輯完全獨(dú)立于父組件的其他邏輯,父組件仍然會(huì)被迫更新。
如果彈窗的顯隱邏輯完全屬于子組件自身(比如一個(gè)“確認(rèn)刪除”彈窗,點(diǎn)擊按鈕后才觸發(fā)關(guān)閉),那么讓父組件管理這個(gè)狀態(tài)就顯得多余,增加了不必要的代碼復(fù)雜度。
方案二:子組件自治——forwardRef
另一種思路是讓子組件自管理狀態(tài),通過useImperativeHandle
暴露控制方法給父組件,看一段代碼:
// 子組件 const Modal = forwardRef((props, ref) => { const [visible, setVisible] = useState(false); useImperativeHandle(ref, () => ({ open: () => setVisible(true), close: () => setVisible(false) })); return visible ? ( <div className="modal"> <button onClick={() => setVisible(false)}>關(guān)閉</button> </div> ) : null; }); // 父組件 function Parent() { const modalRef = useRef(); return ( <div> <button onClick={() => modalRef.current?.open()}>打開彈窗</button> <Modal ref={modalRef} /> </div> ); }
優(yōu)點(diǎn):
父組件極簡主義父組件無需維護(hù)任何狀態(tài),尤其適合多個(gè)彈窗的場景。調(diào)用modalRef.current.open()
簡單直接,避免狀態(tài)聲明污染,也可以避免父組件及其所有子組件重新渲染。
痛點(diǎn):
- 打破組件封裝性父組件對子組件內(nèi)部方法了如指掌,形成緊耦合。一旦子組件重構(gòu)方法名,所有父組件都需要同步修改。
- 代碼復(fù)雜度每個(gè)組件都需要包裹forwardRef ,對于代碼開發(fā)不是特別方便。
如何抉擇?
父組件狀態(tài)管理:
- 彈窗顯隱與父組件狀態(tài)強(qiáng)相關(guān)(如表單提交成功后才展示)
- 需要嚴(yán)格遵循單向數(shù)據(jù)流,方便狀態(tài)追溯
- 彈窗內(nèi)部需要每次打開重置狀態(tài)
forwardRef方案:
- 同一彈窗在多個(gè)分散位置觸發(fā)(如頁面頭部和底部都有觸發(fā)按鈕)
- 彈窗需要保持內(nèi)部狀態(tài)(如填寫了一半的評論框臨時(shí)關(guān)閉)
- 父組件層級過深,prop drilling成本過高
總結(jié)
到底是使用父組件維護(hù)還是使用forwardRef, 這取決于具體項(xiàng)目業(yè)務(wù)的需要 , 如果你的項(xiàng)目里彈窗的顯隱邏輯更多是子組件自己的事,而不是父組件的核心邏輯,那么forwardRef
可能是更優(yōu)雅的解決方案。反之,如果彈窗的開關(guān)直接影響父組件的核心狀態(tài)(如表單提交、數(shù)據(jù)加載),那么父組件管理仍然是更可靠的選擇。
以上就是React中控制子組件顯示隱藏的兩種方式及對比詳解的詳細(xì)內(nèi)容,更多關(guān)于React控制子組件顯示隱藏的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React Antd中如何設(shè)置表單只輸入數(shù)字
這篇文章主要介紹了React Antd中如何設(shè)置表單只輸入數(shù)字問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06React-router 4 按需加載的實(shí)現(xiàn)方式及原理詳解
本篇文章主要介紹了React-router 4 按需加載的實(shí)現(xiàn)方式及原理詳解,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-05-05React?Native?中實(shí)現(xiàn)倒計(jì)時(shí)功能
這篇文章主要介紹了React?Native中實(shí)現(xiàn)倒計(jì)時(shí)功能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08React之防止按鈕多次點(diǎn)擊事件?重復(fù)提交
這篇文章主要介紹了React之防止按鈕多次點(diǎn)擊事件?重復(fù)提交問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10解決React報(bào)錯(cuò)`value` prop on `input` should&
這篇文章主要為大家介紹了React報(bào)錯(cuò)`value` prop on `input` should not be null解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12