Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

alfianandinugraha
alfianandinugraha

Posted on • Edited on

     

Membuat Compound Components di Reactjs

Selamat datang di post perdana saya tentang Reactjs 😄 Kali ini saya coba bahas salah satu pattern di Reactjs yang paling banyak digunakan yaituCompound Components.

Compound dalam bahasa Indonesia artinya menggabungkan. JadiCompound Components merupakan menggabungkan berapa komponen menjadi satu komponen.

Lhooo kan emang seperti itu kalau komponen di Reactjs 🤔

Nahh bedanya, kalau Compound Component ini komponen nya hanya bisa digunakan dalam scope tertentu saja. Kita contohkan pada HTML biasa. Di HTML terdapat tag<table />,<tbody />, dan<thead />. Tag<tbody /> dan<thead /> ini adalah bagian dari<table /> dan tidak bisa di gunakan diluar<table /> (bisa sih, tapi tidak ada efeknya).

Di komponen Reactjs juga bisa dibuat seperti itu lhoo 😁 Sekarang kita coba bikin studi kasus mengenai komponenModal.

Pertama kita rancang dulu bagian-bagian pada Modal, yaitu:

  • Wrapper
  • Body
  • Footer

Ada 3 bagian utama pada Modal, maka bisa kita buat komponen setiap bagiannya dengan nama:

  • <Modal />, untuk Wrapper
  • <Modal.Body />, untuk Body
  • <Modal.Footer />, untuk Footer

*FYI: Bentuk komponen diatas disebutNamespace Component

Perancangan kita selesai, kini waktunya programming. Pertama-tama saya akan menggunakan Vite + React, kalau kalian pake create-react-app juga tidak masalah dan saya juga menggunakan UI framework yang bernamaMaterial UI.

*Note: kamu tidak perlu berpatok dengan apa yang saya gunakan, kamu bisa menggunakan CRA dengan React-bootstrap serta NPM

Pertama kita inisialisasi proyeknya terlebih dahulu menggunakan vite:

yarn create vite modal-compound--template react
Enter fullscreen modeExit fullscreen mode

Setelah inisialiasi kita buka foldernya dan install dependenciesnya:

cdmodal-compound&& yarninstall
Enter fullscreen modeExit fullscreen mode

Jika sudah di install jalankan dev servernya:

yarn dev
Enter fullscreen modeExit fullscreen mode

Install dependencies yang dibutuhkan:

yarn add @mui/material @emotion/react @emotion/styled react-nanny
Enter fullscreen modeExit fullscreen mode

react-nanny? apaan tuh? itu merupakan utilitas tambahan untuk mencari child dari react children. Mirip seperti slot pada Vue

Kalau sudah di install kini inisialisasiApp.jsx danmain.jsx terlebih dahulu:
App.jsx

import{Button}from"@mui/material";functionApp(){return(<div><Buttonvariant="contained">Open Modal</Button></div>);}exportdefaultApp;
Enter fullscreen modeExit fullscreen mode

main.jsx

importReactfrom"react";importReactDOMfrom"react-dom/client";importAppfrom"./App";ReactDOM.createRoot(document.getElementById("root")).render(<React.StrictMode><App/></React.StrictMode>);
Enter fullscreen modeExit fullscreen mode

Inisialisasi sudah selesai kini kita bermain di komponen modalnya. Coba membuat file di lokasisrc/components/modal/index.jsx yang berisi:

constModalBody=()=>{}constModalFooter=()=>{}constModal=()=>{}exportdefaultModal
Enter fullscreen modeExit fullscreen mode

Setiap komponen sudah dibuat waktunya menambahkan bentuk Namespace menjadi:

constModalBody=()=>{}constModalFooter=()=>{}constModal=()=>{}Modal.Body=ModalBodyModal.Footer=ModalFooterexportdefaultModal
Enter fullscreen modeExit fullscreen mode

Sekarang kita menambahkan propchildren disetiap bagian modal nya. Menjadi:

importReactDOMfrom"react-dom";constModalBody=({children=null})=>{return<main>{children}</main>;};constModalFooter=({children=null})=>{return<footer>{children}</footer>;};constModal=({children=null,open=false})=>{if(!open)returnnull;returnReactDOM.createPortal(<div>{children}</div>,document.getElementById("root"));};Modal.Body=ModalBody;Modal.Footer=ModalFooter;exportdefaultModal;
Enter fullscreen modeExit fullscreen mode

Pada komponen<Modal /> diatas saya menggunakan react-portal agar bisa di render di element dengan idroot

Sekarang kita coba styling simple aja untuk komponen<Modal /> ini:

import{Box,Typography}from"@mui/material";importReactDOMfrom"react-dom";constModalBody=({children=null})=>{return<main>{children}</main>;};constModalFooter=({children=null})=>{return<footer>{children}</footer>;};constModal=({children=null,open=false,title="",onClose=()=>{},})=>{if(!open)returnnull;returnReactDOM.createPortal(<><Boxposition="fixed"zIndex={20}top="50%"left="50%"sx={{transform:"translate(-50%, -50%)"}}boxShadow="rgba(149, 157, 165, 0.2) 0px 8px 24px;"bgcolor="white"p="1rem"borderRadius=".5rem"width="500px"><Boxdisplay="flex"alignItems="center"justifyContent="space-between"><Typographyvariant="h1"fontSize="1.5rem"fontWeight="bold">{title}</Typography><Typographyvariant="caption"onClick={onClose}>            close</Typography></Box></Box><Boxposition="fixed"zIndex={10}bgcolor="rgba(0, 0, 0, 0.5)"width="100%"height="100%"top={0}left={0}/></>,document.getElementById("root"));};Modal.Body=ModalBody;Modal.Footer=ModalFooter;exportdefaultModal;
Enter fullscreen modeExit fullscreen mode

Kini komponen<Modal /> akan menerima propsonClose dantitle. Kita lanjut ke komponenApp.jsx nya:

import{Button}from"@mui/material";import{useState}from"react";importModalfrom"./components/modal";functionApp(){const[isOpen,setIsOpen]=useState(false);consttoggle=()=>setIsOpen((isOpen)=>!isOpen);return(<div><Modalopen={isOpen}title="Simple Modal"onClose={toggle}/><Buttonvariant="contained"onClick={toggle}>        Open Modal</Button></div>);}exportdefaultApp;
Enter fullscreen modeExit fullscreen mode

Hasilnya seperti ini:

Modal dasar

Waktunya penerapan Compound Component 😄 kini saya akan menggunakan utilitasreact-nanny untuk mencari komponen didalam children

import{Box,Typography}from"@mui/material";importReactDOMfrom"react-dom";import{getChildByType}from"react-nanny";constModalBody=({children=null})=>{return<main>{children}</main>;};constModalFooter=({children=null})=>{return<footer>{children}</footer>;};constModal=({children=null,open=false,title="",onClose=()=>{},})=>{constbody=getChildByType(children,ModalBody);constfooter=getChildByType(children,ModalFooter);if(!open)returnnull;returnReactDOM.createPortal(<><Boxposition="fixed"zIndex={20}top="50%"left="50%"sx={{transform:"translate(-50%, -50%)"}}boxShadow="rgba(149, 157, 165, 0.2) 0px 8px 24px;"bgcolor="white"p="1rem"borderRadius=".5rem"width="500px"><Boxdisplay="flex"alignItems="center"justifyContent="space-between"><Typographyvariant="h1"fontSize="1.5rem"fontWeight="bold">{title}</Typography><Typographyvariant="caption"onClick={onClose}>            close</Typography></Box>{body}{footer}</Box><Boxposition="fixed"zIndex={10}bgcolor="rgba(0, 0, 0, 0.5)"width="100%"height="100%"top={0}left={0}/></>,document.getElementById("root"));};Modal.Body=ModalBody;Modal.Footer=ModalFooter;exportdefaultModal;
Enter fullscreen modeExit fullscreen mode

Pada kode ini:

constbody=getChildByType(children,ModalBody);constfooter=getChildByType(children,ModalFooter);
Enter fullscreen modeExit fullscreen mode

Digunakan untuk mencari komponen dengan komponen dasarnya. MisalkangetChildByType(children, ModalBody) ini berarti saya mencari komponenModalBody didalamchildren.

Karenachildren ini bisa menerima banyak sekali komponen. Oleh karena itu kita memilih komponen yang dibutuhkan saja. Inilah Compound Components.

Penggunaannya yaitu padaApp.jsx:

import{Button,TextField}from"@mui/material";import{useState}from"react";importModalfrom"./components/modal";functionApp(){const[isOpen,setIsOpen]=useState(false);consttoggle=()=>setIsOpen((isOpen)=>!isOpen);return(<div><Modalopen={isOpen}title="Simple Modal"onClose={toggle}><Modal.Body><TextFieldplaceholder="Masukkan nama"variant="standard"/></Modal.Body><Modal.Footer><Buttonvariant="contained">Simpan</Button></Modal.Footer></Modal><Buttonvariant="contained"onClick={toggle}>        Open Modal</Button></div>);}exportdefaultApp;
Enter fullscreen modeExit fullscreen mode

Hasilnya:

Modal dengan compound component


Maaf kalau desainnya kurang pas, nanti kita perbaiki hehe

Sebentar 🤔 Kok bisaModalBody bisa kepilih padahal kita menggunakanModal.Body bukanModalBody. Nahh ingat, pada komponen<Modal /> kita sudah membuat ini:

Modal.Body=ModalBody;Modal.Footer=ModalFooter;
Enter fullscreen modeExit fullscreen mode

Oleh karena ituModal.Body bisa panggil

Kita coba styling sedikit yaa:
modal/index.jsx

import{Box,Typography}from"@mui/material";importReactDOMfrom"react-dom";import{getChildByType}from"react-nanny";constModalBody=({children=null})=>{return(<Boxcomponent="main"my="1rem">{children}</Box>);};constModalFooter=({children=null})=>{return<footer>{children}</footer>;};constModal=({children=null,open=false,title="",onClose=()=>{},})=>{constbody=getChildByType(children,ModalBody);constfooter=getChildByType(children,ModalFooter);if(!open)returnnull;returnReactDOM.createPortal(<><Boxposition="fixed"zIndex={20}top="50%"left="50%"sx={{transform:"translate(-50%, -50%)"}}boxShadow="rgba(149, 157, 165, 0.2) 0px 8px 24px;"bgcolor="white"p="1rem"borderRadius=".5rem"width="500px"><Boxdisplay="flex"alignItems="center"justifyContent="space-between"><Typographyvariant="h1"fontSize="1.5rem"fontWeight="bold">{title}</Typography><Typographyvariant="caption"onClick={onClose}color="lightgray">            close</Typography></Box>{body}{footer}</Box><Boxposition="fixed"zIndex={10}bgcolor="rgba(0, 0, 0, 0.5)"width="100%"height="100%"top={0}left={0}/></>,document.getElementById("root"));};Modal.Body=ModalBody;Modal.Footer=ModalFooter;exportdefaultModal;
Enter fullscreen modeExit fullscreen mode

App.jsx

import{Button,TextField}from"@mui/material";import{useState}from"react";importModalfrom"./components/modal";functionApp(){const[isOpen,setIsOpen]=useState(false);consttoggle=()=>setIsOpen((isOpen)=>!isOpen);return(<div><Modalopen={isOpen}title="Login"onClose={toggle}><Modal.Body><TextFieldplaceholder="Email"variant="standard"sx={{width:"100%"}}/><TextFieldplaceholder="Password"variant="standard"type="email"sx={{width:"100%",mt:"1rem"}}/></Modal.Body><Modal.Footer><ButtononClick={toggle}variant="contained">            Login</Button></Modal.Footer></Modal><Buttonvariant="contained"onClick={toggle}>        Open Modal</Button></div>);}exportdefaultApp;
Enter fullscreen modeExit fullscreen mode

Hasil nya:

Penambahan style


Lumayanlah yaa

Keuntungan ✨

Apa yaa keuntungan Compound Component ini? sepertinya sama aja mengguankanchildren biasa. Keuntungannya tuh disini:

import{Button,TextField}from"@mui/material";import{useState}from"react";importModalfrom"./components/modal";functionApp(){const[isOpen,setIsOpen]=useState(false);consttoggle=()=>setIsOpen((isOpen)=>!isOpen);return(<div><Modalopen={isOpen}title="Login"onClose={toggle}><Modal.Footer><!--Footerterlebihdahulu--><ButtononClick={toggle}variant="contained">            Login</Button></Modal.Footer><Modal.Body><TextFieldplaceholder="Email"variant="standard"sx={{width:"100%"}}/><TextFieldplaceholder="Password"variant="standard"type="email"sx={{width:"100%",mt:"1rem"}}/></Modal.Body></Modal><Buttonvariant="contained"onClick={toggle}>        Open Modal</Button></div>  );}export default App;
Enter fullscreen modeExit fullscreen mode

Kamu bisa mengisi<Modal.Footer /> terlebih dahulu lalu<Modal.Body />. Kalau menggunakanchildren biasa, sudah pasti posisinya berubah. Nahh kalau menggunakan Compound Component ini meski posisi di parent nya berubah, tapi didalam komponen Compound nya tidak akan berubah

Hasilnya:

Perubahan posisi

Kekurangan 🔻

Sejauh pengalaman saya, kekurangan dariCompound Components ini adalah setup komponen yang lama. Kita harus mendefinisikan setiap bagiannya (Header, Body, dll). Jadi tetap ada kekurangannya hehe

Penutup

Mungkin itu saja pembahasan mengenai Compound Component pada Reactjs. Kalau menurutmu ini bermanfaat silahkan bagikan ke teman-teman mu yaa 😄

Sampai jumpa di tutorial React selanjutnya 👋

Oh iyaa untuk source code nya kunjungihttps://github.com/alfianandinugraha/modal-compound

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

My name is Alfian Andi from Indonesia, I love anything about front-end development
  • Location
    Yogyakarta
  • Education
    Universitas Teknologi Yogyakarta
  • Joined

More fromalfianandinugraha

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp