React Component Step 1: Break the UI into a component hierarchy
Step 2: Build a static version in React
๋ฆฌ์กํธ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค๊ธฐ ์ ์ ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ ๊ฒ โ JSON API & mockup
๋ฐ์ดํฐ โ ๋ฐฑ์๋์์ JSON ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ๋๋ ค์ฃผ๋ API๋ฅผ ์ ๊ณตํ๋ค๊ณ ๊ฐ์
๋๋ถ๋ถ์ REST API ๋๋ GraphQL
REST API
fetch API๋ฅผ ์ด์ฉํด์ GET, POST, PUT/PATCH, DELETE ์์ฒญ (CRUD ๊ตฌํ) โ Resource ์ค์ฌ
GraphQL
Graph ์๋ฃ๊ตฌ์กฐ๋ฅผ ์ด์ฉ
Query์์ ์ป๊ณ ์ ํ๋ ๊ฒ์ ์ง์
ํฌ์คํธ๋ง ๊ฐ์ ธ์ฌ๊ฑด์ง, ํฌ์คํธ์ ๋ธ๋ ค์๋ ๋๊ธ๊น์ง ๊ฐ์ ธ์ฌ๊ฑด์ง
Query(Read), Mutation(Command: Create, Update, Delete), Subscription(์ด๋ฒคํธ๋ฅผ ์ธ์งํ๋ ์ฉ๋)
REST API์ GraphQL ๋ ๋ค JSON ํํ๋ก ๋๋ ค์ฃผ๊ณ ํํ๋ ์ด๋ฐ ์
1 2 3 4 5 6 7 8 [ { category : 'Fruits' , price : '$1' , stocked : true , name : 'Apple' }, { category : 'Fruits' , price : '$1' , stocked : true , name : 'Dragonfruit' }, { category : 'Fruits' , price : '$2' , stocked : false , name : 'Passionfruit' }, { category : 'Vegetables' , price : '$2' , stocked : true , name : 'Spinach' }, { category : 'Vegetables' , price : '$4' , stocked : false , name : 'Pumpkin' }, { category : 'Vegetables' , price : '$1' , stocked : true , name : 'Peas' }, ];
์ค์ JSON์๋ key๋ก ์ฌ์ฉํ ์ ์๋ ๊ฒ๋ค์ ๋ฃ์ด์ค๋ค.
F/E๋ ์ด๋ฐ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉ์๊ฐ ๋ณผ ์ ์๋๋ก UI๋ฅผ ๊ตฌ์ฑ.
React๋ ์ ์ธํ์ผ๋ก UI๋ฅผ ๊ตฌ์ฑํ ์ ์๋ค. (DSL์ ์ฌ์ฉ, HTML๊ณผ ์ ์ฌํ ๋ชจ์)
์ปดํฌ๋ํธ ๊ณ์ธต ๊ตฌ์กฐ
React์ ๊ฐ๋ ฅํ ํน์ง ์ค ํ๋
Component-Based
๊ฐ๋จํ ์ปดํฌ๋ํธ์ ์กฐ๋ฆฝ์ผ๋ก ๋ณต์กํ UI๋ฅผ ๊ตฌ์ฑํ๋ค.
๋ฐ๋๋ก ๋งํ๋ฉด ์ปดํฌ๋ํธ ํ๋ํ๋๋ ๋ณต์กํ์ง ์์์ผ ํ๋ค.
๊ฐ๋จํ ์ปดํฌ๋ํธ์ ๊ธฐ์ค์?
SRP(๋จ์ผ ์ฑ
์ ์์น)
CSS โ ์ด๋ฏธ ์๊ณ ์๋ ๊ธฐ์ค์ ์ฌํ์ฉ.
Designโs Layer
Information Architecture (JSON Schema์ ์ํฅ) โ ์ค์ ๋ก ์์ฒญ ๋ง์ด ์ฐ๊ฒ ๋จ. ์์ฐ์ค๋ฌ์ด SRP๋ฅผ ์ํด์ ์ฌ์ค์ ๊ฐ์ ๋จ.
์์ ์ปดํฌ๋ํธ = ๋ถํ
์ ๋ง๋ค์ด์ ์กฐ๋ฆฝ. ์กฐํฉ์ ๊ฐ์ง์๋ฅผ ํญ๋ฐ์ ์ผ๋ก ๋๋ฆด ์ ์๋ ๊ฐ์ฅ ์ ํ์ ์ธ ๋ฐฉ๋ฒ.
Atomic Design ์ ์ฐ๋ฆฌ๊ฐ ์ ์๊ณ ์๋ ๊ณ์ธตํ ๊ตฌ์กฐ๋ฅผ ๋ช ๊ฐ์ง ์นดํ
๊ณ ๋ฆฌ๋ก ๋ฌถ์ ๋ฐฉ๋ฒ.
Build a static version in React (์ ์ ์ธ ๊ฒ ๋จผ์ ๋ง๋ค๊ธฐ)
๊ฒ์, ์ฒดํฌ๋ฐ์ค1 2 3 4 5 6 7 8 9 <div className="search-bar" > <div > <input type ="text" placeholder ="Search..." /> </div > <div > <input type ="checkbox" id ="only-stock" /> <label htmlFor ="only-stock" > Only Show products in stock</label > </div > </div>
ํ
์ด๋ธ1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <table className="products-tables" > <thead > <tr > <th > Name</th > <th > Price</th > </tr > </thead > <tbody > <tr > <td colSpan ={2} > ์นดํ
๊ณ ๋ฆฌ</td > </tr > <tr > <td > Apple</td > <td > $1</td > </tr > <tr > <td > Dragonfruit</td > <td > $2</td > </tr > </tbody > </table>
๐ ์ค์ ๋ฐ์ดํฐ๋ก ํ๋ฉด์ ๋ ๋๋งํ๊ธฐ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <table className="products-tables" > <thead > <tr > <th > Name</th > <th > Price</th > </tr > </thead > <tbody > <tr > <td colSpan ={2} > {products[0].category}</td > </tr > {products.map((product) => ( <tr > <td > {product.name}</td > <td > {product.price}</td > </tr > ))} </tbody > </table>
โkeyโ prop
์ด ํ์ํ ์ด์ ๋ฌด์ธ๊ฐ ๋ณ๊ฒฝ๋์์ ๋ ๊ฐ๊ฐ์ ๊ตฌ๋ถํ ์ ์๋ ๊ฒ์ด key์ ์ญํ . ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ key๋ uniqueํด์ผ ํ๋ค. 1 2 3 4 5 6 7 8 { products.map ((product ) => ( <tr key ={product.name} > <td > {product.name}</td > <td > {product.price}</td > </tr > )); }
์นดํ
๊ณ ๋ฆฌ๊ฐ 2๊ฐ์ด๊ธฐ ๋๋ฌธ์ ์นดํ
๊ณ ๋ฆฌ์ ๋ง๊ฒ ์ํ ๋ฆฌ์คํธ๊ฐ ๋ณด์ฌ์ผ ํ๋ค.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 export default function App ( ) { const categories = products.reduce ( (acc, product ) => acc.includes (product.category ) ? acc : [...acc, product.category ], [] ); <table className ="products-tables" > <thead > <tr > <th > Name</th > <th > Price</th > </tr > </thead > <tbody > <tr > <td colSpan ={2} > {categories[0]}</td > </tr > {products .filter((product) => product.category === categories[0]) .map((product) => ( <tr key ={product.name} > <td > {product.name}</td > <td > {product.price}</td > </tr > ))} <tr > <td colSpan ={2} > {categories[1]}</td > </tr > {products .filter((product) => product.category === categories[1]) .map((product) => ( <tr key ={product.name} > <td > {product.name}</td > <td > {product.price}</td > </tr > ))} </tbody > </table > ;}
์ฝ๋์ ๋นจ๊ฐ ์ค์ด ๊ฐ์๋ ์ด์
Type โstring[]โ is missing the following properties from type โ{ category: string; price: string; stocked: boolean; name: string; }โ: category, price, stocked, name
๐๐ปย ํ์
์ด ์๋ค๋ ์๊ธฐ
1๏ธโฃ ์ฒซ ๋ฒ์งธ ํด๊ฒฐ ๋ฐฉ๋ฒ
: ๊ธฐ๋ณธ ๊ฐ์ ์ค์ ํ ๋ ํ์
์ง์
1 2 3 4 const categories = products.reduce ( (acc, product ) => (acc.includes (product.category ) ? acc : [...acc, product.category ]), [] as string[] );
2๏ธโฃ ๋ ๋ฒ์งธ ํด๊ฒฐ ๋ฐฉ๋ฒ
: ๋งค๊ฐ๋ณ์์์ ํ์
์ง์
1 2 3 4 5 const categories = products.reduce ( (acc: string[], product ) => acc.includes (product.category ) ? acc : [...acc, product.category ], [] );
3๏ธโฃ ์ธ ๋ฒ์งธ ํด๊ฒฐ ๋ฐฉ๋ฒ
: Type or Interface
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 interface Product { category : string; price : string; stocked : boolean; name : string; } const products : Product [] = [ { category : 'Fruits' , price : '$1' , stocked : true , name : 'Apple' , }, { category : 'Fruits' , price : '$1' , stocked : true , name : 'Dragonfruit' , }, ... ]; export default function App ( ) { const categories = products.reduce ( (acc: string[], product: Product ) => (acc.includes (product.category ) ? acc : [...acc, product.category ]), [] ); ... }
๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ interface.
products์์ name ํ๋๊ฐ ๋น ์ ธ์๋ ์ํฉ์ผ ๋ ์ค๋ฅ๋ฅผ ๋ฐ์์ํจ๋ค.
Extract Function
Inline Function
์์ฃผ ํํ ์ฐ์ด๋ SRP๋ฅผ ์ํ ์๋จ. ๋ณํ์ ํฌ๊ธฐ(์ํฅ ๋ฒ์)๋ฅผ ์ ์ฝํ๋ค.
์ผ๋จ ๊ธธ๊ฒ ์ฝ๋๋ฅผ ์์ฑํ๊ณ , ์ ์ ํ ์๋ฅผ ์ ์๋ ๋ถ๋ถ์ด ๋ณด์ผ ๋ โํจ์๋ก ์ถ์ถโํ๋ค. ๋๋ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ด๋ ค์ด ์ํฉ์ ์ง๋ฉดํ์ ๋ ํจ์๋ก ์ถ์ถ. ๋ฐ๋ก ๋ค๋ฅธ ํ์ผ์ ๋ง๋ค์ด์ผ ํ๋ค๊ณ ์๊ฐํ์ง ์์๋ ๋จ. ์ปดํฌ๋ํธ ๋๋๋ ๊ธฐ์ค์ด ์ ๋งคํ๋ฉด ๋ค์ ํ๋์ ์ปดํฌ๋ํธ๋ก ํฉ์ณค๋ค๊ฐ(Inline Method) ๋ค์ ๋๋ ์ค๋ ๋๋ค.
ํ์ฌ App.tsx๋ ๋๋ฌด ๋ง์ ์ผ์ ํ๊ณ ์๋ค.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 interface Product { category : string; price : string; stocked : boolean; name : string; } const products : Product [] = [ { category : 'Fruits' , price : '$1' , stocked : true , name : 'Apple' , }, { category : 'Fruits' , price : '$1' , stocked : true , name : 'Dragonfruit' , }, { category : 'Fruits' , price : '$2' , stocked : false , name : 'Passionfruit' , }, { category : 'Vegetables' , price : '$2' , stocked : true , name : 'Spinach' , }, { category : 'Vegetables' , price : '$4' , stocked : false , name : 'Pumpkin' , }, { category : 'Vegetables' , price : '$1' , stocked : true , name : 'Peas' , }, ]; export default function App ( ) { const categories = products.reduce ( (acc: string[], product: Product ) => acc.includes (product.category ) ? acc : [...acc, product.category ], [] ); console .log (categories); return ( <div className ="filterable-product-table" > <div className ="seach-bar" > <div > <input type ="text" placeholder ="Search..." /> </div > <div > <input type ="checkbox" id ="only-stock" /> <label htmlFor ="only-stock" > Only Show products in stock</label > </div > </div > <table className ="product-table" > <thead > <tr > <th > Name</th > <th > Price</th > </tr > </thead > <tbody > <tr > <td colSpan ={2} > {products[0].category}</td > </tr > {products .filter((product) => product.category === categories[0]) .map((product) => ( <tr key ={product.name} > <td > {product.name}</td > <td > {product.price}</td > </tr > ))} <tr > <td colSpan ={2} > {categories[1]}</td > </tr > {products .filter((product) => product.category === categories[1]) .map((product) => ( <tr key ={product.name} > <td > {product.name}</td > <td > {product.price}</td > </tr > ))} </tbody > </table > </div > ); }
SRP ์์น์ ์๋ฐํ๊ณ ์๋ ์ํ.
์ฌ์ฌ์ฉํ ์ ์๋๋ก ์ปดํฌ๋ํธ ๋ถ๋ฆฌํ๊ธฐ
๐ย ๋ถ๋ฆฌํ ์ปดํฌ๋ํธ ๐๐ปย ์ํ์ด๋ฆ, ๊ฐ๊ฒฉ์ ๋ํ๋ด๋ ๋ถ๋ถ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <tr> <td colSpan ={2} > {categories[1]}</td > </tr>; { products .filter ((product ) => product.category === categories[1 ]) .map ((product ) => ( <tr key ={product.name} > <td > {product.name}</td > <td > {product.price}</td > </tr > )); } function ProductInCategory ({ category, products }: ProductsInCategoryProps ) { const productsInCategory = products.filter ( (product ) => product.category === category ); return ( <> <tr > <td colSpan ={2} > {products[0].category}</td > </tr > {productsInCategory.map((product) => ( <tr key ={product.name} > <td > {product.name}</td > <td > {product.price}</td > </tr > ))} </> ); }
์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด?
1 <ProductInCategory category={categories[0 ]} products={products} />
1 2 3 4 5 6 7 8 9 10 11 12 <table className="product-table" > <thead > <tr > <th > Name</th > <th > Price</th > </tr > </thead > <tbody > <ProductInCategory category ={categories[0]} products ={products} /> <ProductInCategory category ={categories[1]} products ={products} /> </tbody > </table>
ProductInCategory ์ปดํฌ๋ํธ๊ฐ ๋ฐ๋ณต๋๊ณ ์์ผ๋ฏ๋ก map ํจ์๋ฅผ ์ฌ์ฉํ๋ค.
1 2 3 4 5 { categories.map ((category ) => ( <ProductInCategory key ={category} category ={category} products ={products} /> )); }
ProductInCategory ์ปดํฌ๋ํธ ์ธ๋ถ๋ก ์ถ์ถํ๊ธฐ
๐๐ปย type์ด ์๋ค๋ ์ค๋ฅ
์ด์ ์ ์ผ๋ interface Product๋ App์์๋ ์ฐ๊ณ ์๊ณ , ProductInCategory ์ปดํฌ๋ํธ์์๋ ์ฌ์ฉํด์ผ ํ๋ค.
์ด๋ ์ฌ๋ฌ ํ์
์ ๊ด๋ฆฌํ ์ ์๋๋ก types๋ผ๋ ํด๋์ ๋ฃ์ด๋๋๋ค.
1 2 3 4 5 6 7 8 interface Product { category : string; price : string; stocked : boolean; name : string; } export default Product ;
ProductInCategory์ ์๋ product.name๊ณผ product.price๋ ์ปดํฌ๋ํธ๋ก ์ฒ๋ฆฌํ ์ ์๋ค.
1 2 3 4 5 6 7 8 9 10 import Product from '../types/Product' ;export default function ProductRow ({ product }: { product: Product } ) { return ( <tr > <td > {product.name}</td > <td > {product.price}</td > </tr > ); }
{ product: Product }
์ด ๋ถ๋ถ๋ ๋ฐ๋ก ๋นผ์ฃผ๊ธฐ
1 2 3 4 5 6 7 8 9 10 11 12 type ProductRowProps = { product : Product , }; export default function ProductRow ({ product }: ProductRowProps ) { return ( <tr > <td > {product.name}</td > <td > {product.price}</td > </tr > ); }
Category ์ปดํฌ๋ํธ ๋ง๋ค๊ธฐ ๐๐ปย ์ํ ์นดํ
๊ณ ๋ฆฌ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋ ์ปดํฌ๋ํธ 1 2 3 4 5 6 7 8 9 10 11 <Category category={category} />; export default function Category ({ category }: { category: string } ) { return ( <tr > <td colSpan ={2} > {category}</td > </tr > ); }
+) ์ฐ๋ฆฌ๊ฐ ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ ์ ๋ฆฌํ ์ ์๋ค๋ฉด ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ์ ์๋ค.๋ฐ์ดํฐ๋ฅผ ๋ฐ์์จ ๊ทธ๋๋ก ์ฌ์ฉํ๊ณ ์๋๋ฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํด์ ์ฌ์ฉํ ์ ์๋ค.
category๊ฐ products๋ฅผ ๊ฐ์ง๊ณ ์๊ฒ ๋๋ฉด?
ProductTable ์ปดํฌ๋ํธ ๋ง๋ค๊ธฐ
.filterable-product-table
๋ถ๋ถ์์ category๋ฅผ ์ฐ๊ณ ์์ง ์์ผ๋ categories๋ฅผ ProductTable ์ปดํฌ๋ํธ ์์ผ๋ก ๋ฃ๋๋ค.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 function ProductTable ({ products }: { products: Product[] } ) { const categories = products.reduce ( (acc: string[], product: Product ) => acc.includes (product.category ) ? acc : [...acc, product.category ], [] ); return ( <table className ="product-table" > <thead > <tr > <th > Name</th > <th > Price</th > </tr > </thead > <tbody > {categories.map((category) => ( <ProductInCategory key ={category} category ={category} products ={products} /> ))} </tbody > </table > ); }
products.filter()
ํจ์ ๋ถ๋ถ์ ๋ฐ๋ก ์ถ์ถํ๋ ์์ :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 export default function ProductInCategory ({ category, products, }: ProductsInCategoryProps ) { const productsInCategory = products.filter ( (product ) => product.category === category ); return ( <> <Category category ={category} /> {productsInCategory.map((product) => ( <ProductCategoryRow key ={product.name} product ={product} /> ))} </> ); }
utils > select.ts ์์ฑ
1 2 3 export default function select (items: any[], field: string, value: any ) { return items.filter ((item ) => item[field] === value); }
1 2 3 4 5 6 7 const productsInCategory = products.filter ( (product ) => product.category === category ); โฌ๏ธ const productsInCategory = selectProducts (products, 'category' , category);
SearchBar ์ปดํฌ๋ํธ ์ถ์ถ 1 2 3 4 5 6 7 8 9 10 11 12 13 export default function SearchBar ( ) { return ( <div className ="seach-bar" > <div > <input type ="text" placeholder ="Search..." /> </div > <div > <input type ="checkbox" id ="only-stock" /> <label htmlFor ="only-stock" > Only Show products in stock</label > </div > </div > ); }
FilterableProductTable ์ปดํฌ๋ํธ ์ถ์ถ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import ProductTable from './ProductTable' ;import SearchBar from './SearchBar' ;import Product from '../types/Product' ;type FilterableProductTableProps = { products : Product [], }; export default function FilterableProductTable ({ products, }: FilterableProductTableProps ) { return ( <div > <SearchBar /> <ProductTable products ={products} /> </div > ); }
App ์ปดํฌ๋ํธ๊ฐ ๊ต์ฅํ ๊น๋ํด์ง ๊ฒ์ ๋ณผ ์ ์๋ค.
๐ฅ Props๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ๋๊ฒจ์ค ์ ์๋ ๋ฐฉ๋ฒ๋ ์๋ค.
์๋ฅผ ๋ค์ด, ProductInCategory
์ปดํฌ๋ํธ์์ product={product}
๋ก ๋๊ฒจ์ฃผ๋ ๊ฒ์ด ์๋๋ผ ๊ฐ๋ณ์ ์ผ๋ก ๋๊ฒจ์ค ์๋ ์๋ค.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 return ( <> <Category category ={category} /> {productsInCategory.map((product) => ( <ProductCategoryRow key ={product.name} product ={product} /> ))} </> ); return ( <> <Category category ={category} /> {productsInCategory.map((product) => ( <ProductCategoryRow key ={product.name} name ={product.name} price ={product.price} /> ))} </> );
ํ์ง๋ง typeScript๋ฅผ ์ฌ์ฉํ ๋ ์ ์ฒด๋ฅผ ๋๊ฒจ์ฃผ๋ ๊ฒ์ด ๋ ๊ฐ๋ ฅํ๊ธฐ ๋๋ฌธ์ ์ถ์ฒํ๋ค.
์๋ฅผ ๋ค์ด products ์์์ isStocked๋ผ๋ ์์ฑ์ด ํ๋ ๋ ์ถ๊ฐ๋๋ค๊ณ ๊ฐ์ ํด๋ณด์. ์ด๋ props๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ๋๊ฒจ์คฌ๋ค๋ฉด interface ๋ฟ๋ง ์๋๋ผ props๋ ์์ ์ ํด์ผํ๋ ๋ฒ๊ฑฐ๋ก์์ด ์๊ธด๋ค.
CheckBoxField ์ปดํฌ๋ํธ ์ถ์ถํ๊ธฐ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function CheckBoxField ({ label }: { label: string } ) { const id = `checkbox-${label} ` .replace (/ /g , '-' ).toLowerCase (); return ( <div > <input type ="checkbox" id ={id} /> <label htmlFor ={id} > {label}</label > </div > ); } export default function SearchBar ( ) { return ( <div className ="seach-bar" > <div > <input type ="text" placeholder ="Search..." /> </div > <CheckBoxField label ="Only Show products in stock" /> </div > ); }
const id =
checkbox-${label}.replace(/ /g, '-').toLowerCase();
์ ๊ฐ์ ์ฝ๋๋ React์์ useRef๋ฅผ ์ฌ์ฉํ๋ค.
1 2 3 4 5 6 7 const id = useRef (`checkbox-${label} ` .replace (/ /g , '-' ).toLowerCase ());return ( <div > <input type ="checkbox" id ={id.current} /> <label htmlFor ={id.current} > {label}</label > </div > );