์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก๊ฐ ์๋๋ฏ๋ก ์ฐ์ ์์๊ฐ ๋ฎ์ต๋๋ค. ๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๋ ์ฌ์ ํ ํ ๋ก ํ๊ณ ๊ทธ๊ฒ์ ๊ฐ์ ํ๊ธฐ ์ํด ๋ ธ๋ ฅํ ์ ์์ต๋๋ค.
Menu
Menu.SubMenu
Menu.MenuItem
, ํค๋ณด๋ ์์
์ ์ํด ๋ํ ํ ์ ์์ instance.onKeyDown
https://github.com/ant-design/ant-design/issues ์ ์์กด Table.Column
, Table
๊ฒฝ์ฐ ๊ตฌ์ฑ์ผ๋ก children[n].props
๋ฅผ ์ฝ์ผ๋ฉฐ ์ด์ ์ด๋ฆฐ์ด ์์ ์ฃผ์ ์ํ์ ์ฝ์ ์ ์์ต๋๋ค https://github.com/ant-design/ant-design/issues / 4029 https://github.com/ant-design/ant-design/issues/4324Collpase.Panel
, Collapse
๊ฒฝ์ฐ ์ ๋ชฉ์ผ๋ก children[n].header
๋ฉ๋๋ค.Tabs.TabPane
, Tabs
๊ฒฝ์ฐ TabBar๋ฅผ ์์ฑํ๊ธฐ ์ํด children[n].tab
๋ฅผ ์ฝ์ต๋๋ค. https://github.com/ant-design/ant-design/issues/5165Select.Option
, Select
๋ ์ต์
์ key
์ํ์ ๋ฐ๋ผ ๋ค๋ฆ
๋๋ค.Descriptions.Item
https://github.com/ant-design/ant-design/issues/27411API์ ์ผ๋ถ๋ก key
๋ฅผ ์ฌ์ฉํ๋ ์ผ๋ถ ๊ตฌ์ฑ ์์์ ๊ฒฝ์ฐ ๋ชจ๋ API ์ด๋ฆ์ ์ด๋ฆ์ ๋ฐ๊ฟ ๋๊น์ง์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค. ์
key => id
expandedKeys => expandedIds
selectedKeys => selectedIds
....
๋ธ๋ ์ดํน ์ฒด์ธ์ง์ด์ง๋ง ์ด๋ฌํ ์ข ๋ฅ์ ๋ธ๋ ์ดํน ์ฒด์ธ์ง๋ antd-codemod ๋ก ํด๊ฒฐํ ์ ์์ต๋๋ค.
๊ทธ๋์ ๊ทธ๋ ๊ฒ ํ ๊ฐ์น๊ฐ ์๋ค๊ณ ์๊ฐํ์ญ๋๊น?
๋๋ ์ด๊ฒ์ด ์ข์ ์๊ฐ์ด๋ผ๊ณ ์๊ฐํ์ง ์์ต๋๋ค.
codemod ์๋ฃจ์
์ ํฌ์ด ์๋๋๋ค.
๋ด ๊ด์ ์ ๋ถ๊ณผํ์ง๋ง ์ฌํ๊ฒ๋ ๋๋ถ๋ถ์ ์ฌ๋๋ค์๊ฒ ํ์๋ฐ๋ ๊ฒ๋ณด๋ค ๋ ๋ฐ๋ฐ ์ ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ปดํฌ๋ํธ๋ฅผ ์ปค์คํ ์ปดํฌ๋ํธ์ ์๋ฒ ๋ํ๋ ๊ฒ์ React์ ์ผ๋ฐ์ ์ธ ๊ดํ์ ๋๋ค.
๊ทธ๊ฒ์ ๊ณ ์น๊ณ ์์ฌ์ ์ฌ์ง์์ด ๊ฐ๋ฏธ ๋์์ธ ์ฑํ์ด ๋น ๋ฅด๊ฒ ์ฆ๊ฐํ๋ ๊ฒ์๋ณด์ญ์์ค.
Ant Design์ ์ ๋ง ๋งค๋ ฅ์ ์ด๋ฉฐ react-bootstrap์ ๋ ๋๊ณ ์ถ์ ์ฒซ ๋ฒ์งธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
๋ฟก ๋นต๋จ
API์ ์ผ๋ถ๋ก ํค๋ฅผ ์ฌ์ฉํ๋ ์ผ๋ถ ๊ตฌ์ฑ ์์์ ๊ฒฝ์ฐ ๋ชจ๋ API ์ด๋ฆ์ ์ด๋ฆ์ ๋ฐ๊ฟ ๋๊น์ง์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
@ afc163 ํด๋น API์ ์ด๋ฆ์ ๋ฐ๊ฟ ์ ์์ผ๋ฉด์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ ๊ณต ํ ์ ์์ต๋๋ค. https://github.com/react-component/collapse/issues/73#issuecomment -323626120
์ด๊ฒ์ ๋ฌธ์์ ์ถ๊ฐํด์ผํ๋ค๊ณ ์๊ฐํ์ญ๋๊น?
@benjycui ์ดํดํฉ๋๋ค.
์ด์จ๋ ๊ทธ๊ฒ์ ๊ฒฐ๊ตญ ์ฐจ๋จ๋์ง ์์ต๋๋ค.
์๊ฐ์๋ด์ด ๋ต๋ณ ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
@benjycui ๋น์ ์ด ์ ์ํ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์กฐ์ฌํ๊ณ ์์์ง๋ง ์ ์ ํ ํด๊ฒฐ์ฑ
์ด ์๋๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ๊ตฌ์ฑ ์์๋ฅผ ๋ํ ํ ๋ ๋ด๋ถ ์ํ๋ ๊ฐ๊ธฐ๋ฅผ ์ํฉ๋๋ค. ์ ์ ๋ ์๋ฃจ์
์ผ๋ก๋ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
๋ํ ์ด๊ฒ์ ์์ ๋ฌธ์ ๊ฐ ์๋๋ผ๊ณ ์๊ฐํฉ๋๋ค. ๊ณตํต ๊ตฌ์ฑ ์์๋ฅผ ๊ฒฉ๋ฆฌ ํ ์ โโ์๋ค๋ ๊ฒ์ ์์ฉ ํ๋ก๊ทธ๋จ ๋ด์์ ๋์ผํ ์ฝ๋๊ฐ ์ฌ๋ฌ ๋ฒ ๋ฐ๋ณต๋๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ์์ฉ ํ๋ก๊ทธ๋จ์ด ํฌ๋ฉด antd๋ฅผ ์ ํ ์ฑํํ์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค. ๊ฑด์ค์ ์ธ ๋นํ๊ฐ๋ก ๊ฐ์ฃผํ์ญ์์ค.
์์
ํด ์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค!
์ด๊ฒ์ ์์ ๋ฌธ์ ๊ฐ ์๋๋ฉฐ Ant Design ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ธฐ ์์ํ์ ๋ ์์ํ์ง ๋ชปํ ๋ฌธ์ ๋ผ๊ณ ๋์ํ์ต๋๋ค. ์ฌ์ฉ์ ์ ์ ๊ตฌ์ฑ ์์์ ๋ชจ๋ฒ ์ฌ๋ก๋ React ํ๋ก์ ํธ ์ ์ฒด์์ ์ฌ์ฉ๋ฉ๋๋ค. ๊ฐ์ธ์ ์ผ๋ก ์ ๋ Ant Design์ ์ ๋ง ์ข์ํ์ง๋ง ์ผ๋ถ์๊ฒ๋ ์ด๊ฒ์ด ๊ฑฐ๋๋ฅผ ๋ฐฉํด ํ ์ ์์ต๋๋ค. ๋ค๊ฐ์ค๋ Ant Design v3์์์ด ๊ธฐ๋ฅ์ด ๊ฐ์ ๋๋ ๊ฒ์๋ณด๊ณ ์ถ์ต๋๋ค.
v3์์ ์ด์ ๋ํ ํด๊ฒฐ์ฑ ์ ์ฐพ์ผ์ญ์์ค.
์ด ํจํค์ง๊ฐ ์ถ์ ๋ ํ ํด๊ฒฐํ ์ ์์ต๋๋ค (์๋ง๋).
๋ฉ๋ด๋ฅผ ์ฌ์ฉํ๊ณ <Icon />
๋ฉ๋ด์ React Router <Link />
ํ๊ทธ๋ฅผ ์ค์ฒฉํ์ฌ navbar๋ฅผ ์์ฑํ๋ ค๊ณ ์๋ํ์ต๋๋ค (์๋ชป๋ ๊ฒฝ์ฐ ์ฃ์กํฉ๋๋ค).
๋ ์ ํธํ๋ ์๋ฃจ์ ์ด ์์ต๋๊น?
IMHO,์ด ์ค๋ ๋๋ ๊ณต์ ๋ฌธ์์ ์์ด์ผํฉ๋๋ค.์ด ๋ฌธ์ ๋ ๋ง์ ์ฌ์ฉ์์๊ฒ ๊ฑฐ๋๋ฅผ ๋ฐฉํด ํ ๊ฐ๋ฅ์ฑ์ด ์๊ธฐ ๋๋ฌธ์
๋๋ค.
๋ฌธ์๋ ์ํ๊ฐ ํ์ํ์ง ์์ ๊ฒฝ์ฐ ๋์์ผ๋ก https://github.com/react-component/collapse/issues/73#issuecomment -323626120์ ์ธ๊ธํด์ผํฉ๋๋ค.
๋๋ ๋ฌธ์์์ ์ด๊ฒ์ ๋ํ ์ธ๊ธ์ ํ์คํ ๊ฐ์ฌํ์ ๊ฒ์ ๋๋ค! ๋๋ ์ด๋ฐ ์ผ์ํ๋ ค๊ณ ํ์ง๋ง ์๋ํ์ง ์๊ธฐ ๋๋ฌธ์ ๋ง์ ์๊ฐ์ ๋ญ๋นํ์ต๋๋ค.
<Collapse>
<MyCollapseItem />
<MyCollapseItem2 />
</Collapse>
MyCollapseItem
& MyCollapseItem2
๋ Collapse.Panel
๋ ๋๋งํฉ๋๋ค.
๋ํ react16์ ์ฌ์ฉํ๋ฉด ๋ ๋์์ ๊ตฌ์ฑ ์์ ๋ฐฐ์ด์ ๋ฐํ ํ ์ ์์ผ๋ฏ๋ก์ด ์์ ์ ์ํํ๋ ๊ฒ์ด ํนํ ๋์์ด ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ค๋ณต ์ฝ๋๋ฅผ ๋ฐฉ์งํ๋ ๊ฒ์ด ์ด๋ ต์ต๋๋ค.
์ด๊ฒ์ ๋ํ ์ ๋ฐ์ดํธ๊ฐ ์์ต๋๊น?
์ด๊ฒ์ ์ค์ ๋ก ์ฐ๋ฆฌ์๊ฒ ์ค์ํ ๋ฌธ์ ์ ๋๋ค. ๋ด๊ฐ ์๊ฐํ ์์๋ ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ์๊ธฐ ๋๋ฌธ์ ์ด๋ฆ ๋ณ๊ฒฝ ๋ธ๋ ์ดํน ์ฒด์ธ์ง์ ํฌํํ๊ฒ ์ต๋๋ค.
์ฌ๊ธฐ๋ ๋์ผํฉ๋๋ค. Tabs.TabPane
๋ฐ Menu.MenuItem
ํฉ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ๋๋จธ์ง ์ํ์ ์ ๋ฌํ ์์๋ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ฐพ์์ต๋๋ค.
React.Children.map(children, (child, index) => { ... })
์ ํจ๊ป ์ฌ์ฉํ๋ฉด ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ์๋ํ์ง ์์ต๋๋ค. ๊ฒฐ๊ตญ ํค ์์ฑ์ mykey/.0
์ ๊ฐ์ ๊ฐ์ ์ป์ต๋๋ค. ์ด๊ฒ์ ์ ๊ฐ ์์
ํ ์์๋ ๊ฒ์ด ์๋๋๋ค. ๋๋ ๋ํ ์์ฑ์ ์ด๋ฆ ๋ณ๊ฒฝ์ ํฌํ ํ ๊ฒ์
๋๋ค.
์ด ๋ฌธ์ ๋ ์ค์ ๋ก ๋๋ฅผ antd์์ ๋ฉ์ด์ง๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๊ตฌ์ฑ ์์๋ฅผ ๋ง๋๋ ๋ฅ๋ ฅ์ด ์ค์ ๋ก ์ ํ๋ฉ๋๋ค.
Menu ๋ด์์ React Router๋ฅผ ์ฌ์ฉํ๋ ค๋ ๋ชจ๋ ์ฌ๋์ ์ํด @yunshuipiao ํญ๋ชฉ ์ # 6576์์ ์ ์๊ฒ ํจ๊ณผ์ ์ธ ์๋ฃจ์ ์ ์ ๊ณตํ์ต๋๋ค.
๋ ๋ค๋ฅธ ์์ ๋ฌธ์ : Menu.Item์ ๋ํํ๋ฉด ํ์ ํญ๋ชฉ ์ค ํ๋๊ฐ ์ ์ด๋ ์ธ๋ก ๋ชจ๋์์ ์ ํ ๋ ๋ ํ์ ๋ฉ๋ด๊ฐ ์ ํ๋ ๊ฒ์ผ๋ก ํ์๋์ง ์์ต๋๋ค. ๊ด๋ จ ๋ผ์ธ :
https://github.com/react-component/menu/blob/018d6f84d622ee140d9695ba57e7a773cf368efa/src/util.js#L40
https://github.com/react-component/menu/blob/018d6f84d622ee140d9695ba57e7a773cf368efa/src/SubMenu.jsx#L314
Collapse๋ฅผ ์ฌ์ฉ์ ์ ์ ๊ตฌ์ฑ ์์๋ก ์์ ํ๋ ค๋ ์ฌ๋๋ค์ ์ํด ์ด๊ฒ์ ๋ฌธ์ํํ๊ณ ์ถ๋ค๊ณ ์๊ฐ
<Collapse>
<Custom/>
<Custom/>
</Collapse>
Custom.render() {
return (
<Panel {...this.props}>
<div>My custom stuff here</div>
</Panel>
)
}
@ncknuna์ ๊ฐ์ ๋ฌธ์ ์ ๋๋ค.
Menu.Item์ ๋ํ ํ ๋ ์ ํ๋์ง ์์ต๋๋ค. ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ์์ต๋๊น?
@Nomeyho ์ ๋ ๊ด๋ จ ๋ฉ์๋๋ฅผ ๋ณต์ฌ / ๋ถ์ฌ ๋ฃ๊ธฐํ๊ณ ์๋ ๊ฒ์ฌ๋ฅผ ์ฃผ์ ์ฒ๋ฆฌํ์ฌ ant-menu-submenu-selected
ํด๋์ค๊ฐ ์ถ๊ฐ๋๋์ง ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ ๋
ผ๋ฆฌ๋ฅผ ์ฌ๊ตฌ์ฑ ํ ๋ค์ ํด๋์ค๋ฅผ ๋ด ๋ํผ์ className
๋ก ์ ๋ฌํ์ต๋๋ค.
function loopMenuItemRecusively (children: Array<any>, keys: Array<string>, ret: { find: boolean }) {
if (!children || ret.find) {
return
}
React.Children.forEach(children, (c: any) => {
if (ret.find) {
return
}
if (c) {
const construt = c.type
// Original check that caused problems. I'm not concerned about omitting it
// because I don't plan on putting a bunch of weird, large stuff in my menus...
// if (!construt || !(construt.isSubMenu || construt.isMenuItem || construt.isMenuItemGroup)) {
// return;
// }
if (keys.indexOf(c.key) !== -1) {
ret.find = true
} else if (c.props && c.props.children) {
loopMenuItemRecusively(c.props.children, keys, ret)
}
}
})
}
function isChildrenSelected (children: Array<any>, selectedKeys: Array<string>) {
const ret = { find: false }
loopMenuItemRecusively(children, selectedKeys, ret)
return ret.find
}
// Omitting other custom code below...
export const SubMenu = ({ children, className, selectedKeys, title, ...rest }: any) => {
const isSelected = isChildrenSelected(children, selectedKeys)
className = [
className,
isSelected ? 'ant-menu-submenu-selected' : ''
].filter(className => classname).join(' ')
return (
<SubMenu title={title} className={className} selectedKeys={selectedKeys} {...rest}>
{children}
</SubMenu>
)
}
์ด๊ฒ์ ๋ํ ์์ ์ฌํญ์ด ์์ต๋๊น?
@ChuckJonas์ ๋์ํฉ๋๋ค.
์ด ๋ฌธ์ ๋ ์ค์ ๋ก ๋๋ฅผ antd์์ ๋ฉ์ด์ง๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๊ตฌ์ฑ ์์๋ฅผ ๋ง๋๋ ๋ฅ๋ ฅ์ด ์ค์ ๋ก ์ ํ๋ฉ๋๋ค.
๋ค์๊ณผ ๊ฐ์ด Menu SubMenu ๋ฐ Menu.items๋ฅผ ์ฌ์ฉํด์ผํฉ๋๋ค.
์? ๋ค๋ฅธ ํ์ด์ง์์ "CustomSubMenu"์์๋ฅผ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ ... ์ด๊ฒ์ "์ฌ์ฌ์ฉ ๊ฐ๋ฅํ"๊ตฌ์ฑ ์์์ ์ค์ํ ๋ถ๋ถ์
๋๋ค.
_MainFile.js_
Import CustomSubMenu from './OtherFile.js';
<Menu>
<CustomSubMenu />
<CustomSubMenu2 />
<CustomSubMenu3 />
</Menu>
๋ฐ OtherFile.js๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
render(){
return(
<SubMenu>
<SubMenu.item />
<SubMenu.item2 />
etc...etc...
</SubMenu>
);
}
ํ์ ๋ฉ๋ด์ ๋ํ ์์ ํด๊ฒฐ ๋ฐฉ๋ฒ (๊ฐ๋จํ๊ฒ ํธ์ง ๋จ) :
const SubMenuArray = ({ ...props }) =>
[1, 2].map(i => (
<Menu.SubMenu {...props} eventKey={`item_${i}`} subMenuKey={`${i}-menu-`} />
));
๋ฐฐ์ด์ ๋ค๋ฃฐ ๋ :
eventKey
๋ฐ subMenuKey
๋ ๋์ ์ ๊ทผ ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
const SubMenuWrapper = ({ children, ...props }) =>
React.Children.map(children, (child, i) =>
React.cloneElement(child, {
...props,
eventKey: `item_${i}`,
subMenuKey: `${i}-menu-`
})
);
์ฉ๋ฒ:
<Menu>
<SubMenuWrapper>
<CustomSubMenu title={"one"}/>
<CustomSubMenu title={"two"}/>
</SubMenuWrapper>
</Menu>
๋ค์ ๋งํ์ง๋ง, ๋ฐฐ์ด์์ ์ธ๋ฑ์ค๋ฅผ ์ฌ์ฉํ๊ณ ์ถ์ง ์์ ๊ฒ์ด๋ฏ๋ก ํ๋ก๋์ ์์ ์ฌ์ฉํ์ง ๋ง์ญ์์ค. ๊ทธ๋ฌ๋ ์์ด๋์ด๋ ํ์คํฉ๋๋ค.
ํค์ ์ข
์์ฑ์ ์ ๊ฑฐ ํ ์์๋ ๋ฐฉ๋ฒ์ด ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋ฉ๋ด๋ฅผ ์๋ก ๋ค์ด itemKey
์ํ์ ๋์
ํ ๋ค์ context
๋ฅผ ์ฌ์ฉํ์ฌ ๋ฉ๋ด๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค. ํธํ์ฑ์ ์ ์งํ๊ธฐ ์ํด ๋ฉ๋ด๋ ์ฌ์ ํ ์์์ ํ์ํ๊ณ key
๋ฅผ itemKey
๋ณ๊ฒฝํฉ๋๋ค. ๋์์ selectedKeys
์ ๊ฐ์ props์ ์๋ฏธ๋ฅผ ์ ์งํ ์๋ ์์ต๋๋ค.
@yesmeck ์์งํ ๋งํด์ ant design
์ฌ์ฉํ์ง ์๊ธฐ ๋๋ฌธ์ ์๊ฐ์ด ๊ฑธ๋ฆฝ๋๋ค ( ํ์ง๋ง ์ด๋ฒ ์ฃผ์ ์ค์ํ ์์ฉ ํ๋ก๊ทธ๋จ์ ์ฌ์ฉํ ๊ณํ์
๋๋ค ).
๋ด๊ฐ ์ดํดํ๋ ํ, ํด๊ฒฐ ๋ฐฉ๋ฒ์ผ๋ก ์๋ก์ด context API
๋ฐ์์ ํ์ฉํ ์ ์์ต๋๊น?
์ข์ ์์์ ๋๋ค
์, ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด cloneElement
๋์ context
๊ฐ ํ์ํฉ๋๋ค.
ํด๊ฒฐ์ฑ ์ "React.Children.forEach"๋ฐ "React.cloneElement"๋ฅผ ์ฌ์ฉํ์ฌ ์ํ์ ์ ๋ฌํ๊ณ ์ ์ํ์ ์ค์ ํ๋ ๊ฒ์ด ์๋๋ผ, ์๋ฅผ ๋ค์ด ์ฌ์ฉ์ ์ง์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.
<Select>
{({ onSelect }) => (
<div>
<Option onClick={onSelect} key="0">option1</Option>
<Option onClick={onSelect} key="1">option2</Option>
</div>
)
</Select>
๊ทธ๋ฆฌ๊ณ antd ์ ํ ์์ค๋ "React.Children.forEach"๋ฐ "React.cloneElement"๋์ ํจ์ ์์ ์ํ์ ์ฌ์ฉํฉ๋๋ค.
์ด๊ฒ์ด ์ด๋ฆฌ์์ ์ง๋ฌธ์ด๋ผ๋ฉด ์ค๋กํฉ๋๋ค.ํ์ง๋ง ์ ๋ ์ฌ์ ํ React์ Ant Design์ ์ต์ํ์ง ์์ต๋๋ค.
์ด๊ฒ์ ์ค์ง์ ์ผ๋ก react-redux ์ฐ๊ฒฐ SPA ๋ด์์ Ant ๋์์ธ ๋ฉ๋ด๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๊น?
๊ทธ๋ ๋ค๋ฉด Ant Design์ผ๋ก ๋น๊ต์ ๋ณต์กํ SPA๋ฅผ ์ด๋ป๊ฒ ์์ฑํ ์ ์์ต๋๊น? ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ์์ต๋๊น?
์ด๊ฒ์ ๋ํ ์ ๋ฐ์ดํธ๊ฐ ์์ต๋๊น?
์ด ๋ฌธ์ ์ ๋ํ ์ ๋ฐ์ดํธ๊ฐ ์์ต๋๊น? ๋ฉ๋ด ํญ๋ชฉ์ด HOC์์ ์ด์ํ๊ฒ ์๋ํฉ๋๋ค.
์๋
ํ์ธ์ ! ์ฌ๊ธฐ์์๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค. ์ ๋ ์ด๋ฌํ ์ข
๋ฅ์ ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฉ์ ์ ์ ํ ์์๋ ๋ฐ ์ ๋ง ๊ด์ฌ์ด ์์ต๋๋ค.
์ฌ์ฉ์ ์ง์ Select.Option
์ค์ ๋ก ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
์ด ์ค๋ ๋์์ ์ ์ ๋ ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ์๋ํ๋ ๋ฐ ๋์์ด๋์ง ์์์ต๋๋ค. ๋น ์ต์ ์ด์๋ ์์ ์ ํ์ด ์์ต๋๋ค ....
import React from 'react';
import PropTypes from 'prop-types';
import { Select } from 'antd';
const { Option } = Select;
const PictureOption = ({ label, value, pictureId, ...props }) => (
<Option label={label} value={value} className="select-item" {...props}>
<div className="select-item__thumbnail">
<img src={pictureId} alt="item-img" />
</div>
<div className="select-item__name">{label}</div>
</Option>
);
PictureOption.propTypes = {
label: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
pictureId: PropTypes.string.isRequired,
};
export default PictureOption;
์ฌ์ฉ์ ๊ถํ์ ๋ฐ๋ผ UI ์์๋ฅผ ๋ ๋๋งํ๊ธฐ ์ํด CASL ์ ์ฌ์ฉํ๊ธฐ ์์ํ์ต๋๋ค. ๊ทธ๋ฌ๋ ์ํ์ด ์์ ์์์ ์ฌ๋ฐ๋ฅด๊ฒ ์ ํ๋์ง ์์ isRootMenu ํจ์์ ๋ํ ํธ์ถ์ด ์คํจํ๊ธฐ ๋๋ฌธ์ SubMenu๊ฐ ๋ ๋๋ง๋์ง ์๋๋ค๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ์ผ๋ก ํ์ ๋ฉ๋ด๋ฅผ ์์๋ก ์ ์ํ๊ณ '์์ผ๋ก'์ํ์ ์ ๋ฌํ์ต๋๋ค.
````
render () {
// ### Administration Menu ###
const AdminMenu = ({ ...props }) => {
return (
<Can I="access" on="admin-content">
<Menu.Divider {...props} />
<Menu.SubMenu
{...props}
title={
// FIXME: Icon is not rendered... :-/
<span>
<Icon type="tools" />
<span>Administration</span>
</span>
}
// title={<span>Administration</span>}
key="admin">
<Menu.Item key="users" tabIndex={0}>
<Icon type="android" />
<span>User Administration</span>
</Menu.Item>
<Menu.Item key="permissions" tabIndex={0}>
<Icon type="lock" />
<span>Permissions</span>
</Menu.Item>
</Menu.SubMenu>
</Can>
);
};
return (
<Layout id="menu-component-layout">
<Layout.Sider width="300px" collapsible="false" trigger={null}>
<Menu theme="dark" mode="inline" defaultSelectedKeys={['user']} defaultOpenKeys={['user', 'config', 'admin']}>
<AdminMenu />
</Menu>
</Layout.Sider>
<Layout.Content id="menu-component-content">
<h3>Page containing a side menu</h3>
</Layout.Content>
</Layout>
);
}
````
์ด ์๋ฃจ์ ์ ๊ทธ๋ค์ง ํธ๋ฆฌํ์ง๋ ์์ง๋ง ์ง๊ธ์ ์๋ํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ฌ์ ํ ์์ด์ฝ์ด ํฌํจ ๋ ํ์ ๋ฉ๋ด์ ์ ๋ชฉ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋ ๋๋ง๋์ง ์๋ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ์์ด์ฝ์ด ์์ต๋๋ค.
๋๊ตฌ๋ ์ง ๊ทธ๊ฒ์ ๊ณ ์น๋ ๋ฐฉ๋ฒ์ ์๊ณ ์์ต๋๊น?
์ฌ๊ธฐ์ ์ผ์ผ์ด์ค๋ฅผ ๋ง๋ค์์ต๋๋ค : https://github.com/gibelium/meteor-react-antd-casl
GitHubant-design UI ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ meteor / react ํ๊ฒฝ์์ CASL ์ธ์ฆ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ ์ผ์ผ์ด์ค-gibelium / meteor-react-antd-casl
@gibelium ์์ด์ฝ ๋ ๋๋ง์ ์ค์ ๋ก ์์ฒด ๋ฌธ์ ๊ฐ ๋ ๊ฐ์น๊ฐ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ๋ณต์ ํ๊ณ ์์ด์ฝ์ ๊ณ ์คํธ ๋ฒํผ์ผ๋ก ๋ฐ๊พธ๋ ค๊ณ ์๋ํ๋๋ฐ ๋ฒํผ ์ค๊ณฝ์ ์ด ํ์๋์ง๋ง ์์ด์ฝ๋ ๋ฒํผ์์ ๋ ๋๋ง๋์ง ์์ต๋๋ค.
@gotjoshua ๊ทธ ์ ์ฉ ๋ฌธ์ ๋ฅผ ๋ง๋ค ๊ฒ์ ๋๊น?
๊ธฐ๋ณธ ํ์ฅ ๋ฉ๋ด ํญ๋ชฉ ์ค์ ๋ ์๋ํ์ง ์์ต๋๋ค. ๋ด ํด๊ฒฐ ๋ฐฉ๋ฒ ๊ตฌํ์ Menu์ defaultOpenKeys
์์ฑ์ ๋ฌด์ํฉ๋๋ค.
๊ทธ๊ฒ์ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์์ด๋์ด๊ฐ ์์ต๋๊น?
์ด ๋ฌธ์ ๋ ๋ฌธ์์์ ์ค์ ๋ก ์ธ๊ธ๋์ด์ผํฉ๋๋ค.์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ ์ดํดํ๊ธฐ ์ํด์ด ๋ฒ๊ทธ๋ฅผ ์กฐ์ฌํ๋ ๋ฐ ํ๋ฃจ ์ข
์ผ ๋ญ๋นํ์ต๋๋ค. ๋ค๋ฅธ ๊ฐ๋ฐ์๊ฐ ๋น์ ์ด ์ํฐ ํจํด์ ์ฌ์ฉํ๊ณ React ํค๋ฅผ ์ค๊ณํ๋ ๊ฒ์ ์์๋ด๋ ๋ฐ ๋๋ฌด ๋ง์ ์๊ฐ์ ๋ญ๋น ํ ํ์๊ฐ ์๋๋ก ๊ฒฝ๊ณ ๋ฅผ ํด์ฃผ์ธ์. ๊ทธ๋ฆฌ๊ณ ์ด์ ๋น์ ์ ์ปค๋ฎค๋ํฐ์์ ์ฌ์ฉํ ์์๋ ๋ง์ HOC ๋๋ ๋ฐ์ฝ๋ ์ดํฐ์ ๋งค์ฐ ์ทจ์ฝํฉ๋๋ค.
์ด๊ฒ์ ์ ๋ง ๋ถ๋๋ฌ์ด ์ผ์
๋๋ค. ๋ค์ ๋ฉ์ด์ ๋ฒ์ ์์ ์์ ํ์๊ธฐ ๋ฐ๋๋๋ค.
์ด ๋ฌธ์ ์ ๋ํ ์ ๋ฐ์ดํธ๊ฐ ์์ต๋๊น? ๋ฉ๋ด defaultOpenKeys ์ค์ ์ด ์๋ํ์ง ์์
์ ๋ง ๋น ๋ฅด๋ฉด ์ฐ์ ์์๊ฐ ๋์ ๊ฒ์ ๋๋ค. ๐ฅ
๋๋ (์๋ง๋) ๊ตฌํํ ์์๋ ์ ์ฌํ ์ฌ์ฉ ์ฌ๋ก๊ฐ ์์ต๋๋ค.
redux ์ ์ฅ์์ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋กํ๋ ์ต์
์ผ๋ก Select
๋ฅผ ๋ ๋๋งํ๋ redux ์ฐ๊ฒฐ ๊ตฌ์ฑ ์์๋ฅผ ๋ง๋ค๊ณ ์ถ์ต๋๋ค. ๋ชจ๋ ๊ณณ์์ ๋์ผํ ์ฝ๋๋ฅผ "๋ณต์ฌ-๋ถ์ฌ ๋ฃ๊ธฐ"ํ๊ณ ์ถ์ง ์๊ธฐ ๋๋ฌธ์ Form.getFieldDecorator
๋ด๋ถ์์์ด ์ ํ์ ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฉํ๊ณ ์ถ์ง๋ง connect
HOC ์ฌ์ฉ์ผ๋ก ์ธํด ํ ์ ์์ต๋๋ค. ๊ทธ๊ฒ.
ํธ์ง : ๋ด ์ฌ์ฉ ์ฌ๋ก์ ๋ํ ํด๊ฒฐ์ฑ
์ ์ฐพ์์ต๋๋ค. ๋ค์๊ณผ ๊ฐ์ด forwardRef
์ต์
์ ์ฌ์ฉํ์ฌ ์์์ ์ค๋ช
ํ ๊ตฌ์ฑ ์์๋ฅผ ๋ง๋ค ์์์์ต๋๋ค.
connect(mapStateToProps, mapDispatchToProps, null, { forwardRef: true })(Component);
์ด ์๋ฃจ์
์ connect
HOC์๋ง ํด๋น๋์ง๋ง React.forwardRef ๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ฌํ ์๋ฃจ์
์ ๋ง๋ค ์ ์์ด์ผํฉ๋๋ค.
์ด์ ์๊ฒฌ์ ๋ง๋ถ์ฌ-์, ์ด๊ฒ์ด ์ฐ์ ์์๋ก ๊ฐ์ฃผ ๋ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ์์์ ์ค๋ช
ํ๋๋ก ๋ฌธ์ ์ค ํ๋๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ํด๊ฒฐ ํ ํ ์ด์ ์ฌ์ฉ์ ์ง์ ๊ตฌ์ฑ ์์๋ก ๋ํ ๋ Tabs.TabPane
๊ตฌ์ฑ ์์๋ฅผ ๋ง๋ค์ด์ผํฉ๋๋ค. ๋งค์ฐ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก-> ๋ํ ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฉํ์ฌ ๊ถํ์ ํ์ธํ๋ฏ๋ก ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๋ฉด ํ์ ๊ตฌ์ฑ ์์๊ฐ ๋ ๋๋ง๋๊ณ ๊ทธ๋ ์ง ์์ผ๋ฉด ๊ทธ๋ ์ง ์์ต๋๋ค.
์ด๊ฒ์ ๋ํ ๊ฐ๋จํ๊ณ ์๋ํ๋ ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ์์ต๋๊น?
์ด๊ฒ์ ๋ํ ์ ๋ฐ์ดํธ๊ฐ ์์ต๋๊น?
๊ธฐ๋ณธ์ ์ผ๋ก ๋๋จธ์ง ์ํ์ ์ ๋ฌํ ์์๋ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ฐพ์์ต๋๋ค.
๋ํ ๋ ๊ตฌ์ฑ ์์์์.
์ฝ์ ๊ฒฝ๊ณ ๊ฐ ํ์๋ฉ๋๋ค. ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ์์ต๋๊น?
index.js:1437 Warning: React does not recognize the
staticContext prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase
staticcontext`. ์ค์๋ก ์์ ๊ตฌ์ฑ ์์์์ ์ ๋ฌํ ๊ฒฝ์ฐ DOM ์์์์ ์ ๊ฑฐํฉ๋๋ค.
index.js : 1437 ๊ฒฝ๊ณ : ์์ฑ dispatch
๊ฐ์ด ์๋ชป๋์์ต๋๋ค.
๊ฐ์ ๋ฌธ์ ... Menu.Item์ ๋ํํ๊ธฐ ์ํด HOC๋ก ๊ถํ ๊ตฌ์ฑ ์์๋ฅผ ๋ง๋ค๊ณ ์ถ์ง๋ง antd๋ ์ด๊ฒ์ ํ์ฉํ์ง ์์ต๋๋ค.
๋๋ ๊ทธ ๋ฌธ์ ์ ์๊ฐ์ ๋ณด๋๋ค ...
๊ทธ๋ฆฌ๊ณ ํ ์ ์์ต๋๋ค ๐, ๋๋จธ์ง ์ํ์ ie์๊ฒ ์ ๋ฌํ๋ฉด๋ฉ๋๋ค. Collapse.Panel (rc-panel์ ์์ค ์ฝ๋๋ฅผ ํ์ธํ์ฌ ์ดํด)
export const CustomPanel: React.FC = ({ header, children, ...props }) => {
// do whatever you like
return <Collapse.Panel header={header} {...props}>
{children}
</Collapse.Panel>
};
๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ์ญ์์ค.
<Collapse>
<CustomPanel key="first" header="Header 1">Body</CustomPanel>
<CustomPanel key="second" header="Header 2">Body</CustomPanel>
</Collapse>
4.0 ๋ฆด๋ฆฌ์ค์์์ด ์๋ฃจ์ ์ ๋ณด๋ ๊ฒ์ด ๋ฉ์ง ๊ฒ์ ๋๋ค!
์ด๊ฒ์ ์ ๋์ ์ผ๋ก ์ต์ฐ์ ์์์
๋๋ค.
๋ฌธ์ ๊ทธ๋๋ก ํน๋ณํ ๋์์ด ํ์ํ ๋ (๋๋ก๋ ๊ถํ ๋ถ์ฌ์ ๊ฐ์ ๊ฐ๋จํ ๋์) ์ด๋ฌํ ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋ง๋ญ๋๋ค.
์๋ฅผ ๋ค์ด ๋์ ์ผ๋ก๋ก๋๋๋ ๋ฉ๋ด๋ฅผ ๋ง๋ค๋ ค๊ณ ํ๋ฏ๋ก ๋ฐ์ดํฐ๊ฐ ๋์ฐฉํ ๋๊น์ง ์ด๋ฆ์ผ๋ก ์คํผ๋๊ฐ์๋ ๋นํ์ฑํ ๋ Menu.Item
๋ฅผ ๋ฌธ์ ๊ทธ๋๋ก ํ์ํฉ๋๋ค.
๊ทธ๊ฒ์ ์ต์ ์ด ์๋๋๋ค.
๋๋ ๊ทธ ๋ฌธ์ ์ ์๊ฐ์ ๋ณด๋๋ค ...
๊ทธ๋ฆฌ๊ณ ํ ์ ์์ต๋๋ค ๐, ๋๋จธ์ง ์ํ์ ie์๊ฒ ์ ๋ฌํ๋ฉด๋ฉ๋๋ค. Collapse.Panel (rc-panel์ ์์ค ์ฝ๋๋ฅผ ํ์ธํ์ฌ ์ดํด)
ํ๋ฅญํ ์๋ฃจ์
์ด์ง๋ง (์ ๋ง๋ก ๋ด ํ๋ก์ ํธ์์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค) ์ผ๋ถ ๊ธฐ๋ฅ์ ์๊ฒ๋ฉ๋๋ค.
์ฆ, <SubMenu>
์ด <Menu>
์ ์ง๊ณ ์์์ด ์๋ ๊ฒฝ์ฐ defaultOpenKeys
๋ ์๋ํ์ง ์์ต๋๋ค. ๐
๋ฐฉ๊ธ์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
๋ฌธ์์์ ํ์ธ์ด ํ์ํฉ๋๋ค. ๋ด ํ๋ก์ ํธ์์ AntDesign์ ์ฌ์ฉํ๋ ๊ฒ์ ์ง์งํ๊ฒ ์ฌ๊ณ ํ๊ฒ ๋ง๋๋์ด ๋ฌธ์ (๋ค๋ฅธ ๋ช ๊ฐ์ง ์ฌ์ํ ๋ฌธ์ ์ค์์)๋ฅผ ์ ํ๊ฒ๋์ด ๋งค์ฐ ์ค๋ง ์ค๋ฝ์ต๋๋ค.
๋๋ ๊ทธ๊ฒ์ ๋ํ ํด๊ฒฐ์ฑ ์ด ์์ง ์๋ค๋ ๊ฒ์ ๋ฏฟ์ ์ ์์ต๋๋ค.
์ด๊ฒ์ ์ ๋ง ๊ณ ์ณ์ผํฉ๋๋ค. ๋๋ถ๋ถ์ ๊ฐ๋ฐ์๋ ์ฆ์ ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค. ์ฆ, ์ ๊ณต๋ api๋ก ์ถ๊ฐ ํ ์์๋ ๋ ๋ง์ ๊ธฐ๋ฅ์ ํตํฉํ๊ณ ์ถ์ ์ ์์ต๋๋ค. ๋๋ HOC๋ฅผ ์ผ๋ฐ์ ์ด์ง ์๊ฑฐ๋ ์ฐ์ ์์๊ฐ ๋ฎ์ ์ฌ์ฉ ์ฌ๋ก๋ผ๊ณ ๋ถ๋ฅด์ง ์์ ๊ฒ์ ๋๋ค. React์ ๊ตฌ์ฑ ์ ํน์ฑ์ ๊ธฐ๋ณธ์ ๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ์์ ํ๊ณ ์์ ๋๋ ๋์ ์ฌ๋๋ค์ด ์ฌ๊ธฐ์์ ์ฐพ์ ํด๊ฒฐ ๋ฐฉ๋ฒ๋ฟ๋ง ์๋๋ผ ์ ๋ณด๋ฅผ ๊ณต์ ๋ฌธ์์ ์ถ๊ฐํ์ญ์์ค.
์ด ๋ฌธ์ ๋ฅผ ์์ ํ๊ณ ์์ ๋๋ ๋์ ์ฌ๋๋ค์ด ์ฌ๊ธฐ์์ ์ฐพ์ ํด๊ฒฐ ๋ฐฉ๋ฒ๋ฟ๋ง ์๋๋ผ ์ ๋ณด๋ฅผ ๊ณต์ ๋ฌธ์์ ์ถ๊ฐํ์ญ์์ค.
์ ์ง ๊ด๋ฆฌ์๋ PR์ ๊ฐ๋ฐฉ๋์ด ์์ผ๋ฉฐ ์ํ๋ ๊ฒฝ์ฐ ๋ฌธ์ ์ ๋ฐ์ดํธ์ ๋ํ PR์ ๋ณด๋ผ ์ ์์ผ๋ฉฐ ์๊ฐ์ด ์์ต๋๋ค.
๋ฟก๋ฟก
๋๋ ๊ทธ ๋ฌธ์ ์ ์๊ฐ์ ๋ณด๋๋ค ...
๊ทธ๋ฆฌ๊ณ ๊ทธ๊ฒ์ ํ ์ ์์ต๋๋ค, ๋น์ ์ ie์ ๋๋จธ์ง ์ํ์ ์ ๋ฌํ๊ธฐ ๋งํ๋ฉด๋ฉ๋๋ค. Collapse.Panel (rc-panel์ ์์ค ์ฝ๋๋ฅผ ํ์ธํ์ฌ ์ดํด)
export const CustomPanel: React.FC = ({ header, children, ...props }) => { // do whatever you like return <Collapse.Panel header={header} {...props}> {children} </Collapse.Panel> };
๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ์ญ์์ค.
<Collapse> <CustomPanel key="first" header="Header 1">Body</CustomPanel> <CustomPanel key="second" header="Header 2">Body</CustomPanel> </Collapse>
๋๊ตฐ๊ฐ ์๋์์ ๋ฌด์จ ์ผ์ด ์ผ์ด๋๊ณ ์๋์ง ์ค๋ช
ํด ์ฃผ์๊ฒ ์ต๋๊น? ๋ํ ๊ตฌ์ฑ ์์ ๋ด์์ Panel
๋ํ์ ์๋ํฉ๋๋ค.
์ด ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ : :
<PersonalInfoPanel
header="header"
key={"personalInfo" + i}
extra={genExtra()}
/>
PersonalInfoPanel
๋ด๋ถ :
function PersonalInfoPanel(props, ref) {
return (
<Panel header={props.header} key={props.key} extra={props.extra}>
...
์๋ํ์ง ์์ต๋๋ค.
๊ทธ๋ฌ๋ ์ด๊ฒ์ ๋์ ์ฌ์ฉํ์๋ง์ :
function PersonalInfoPanel(props, ref) {
return (
<Panel {...props}>
...
์๋ํ๊ธฐ ์์ํฉ๋๋ค.
๋๊ตฐ๊ฐ ์ด์ ๋ฅผ ์ค๋ช
ํ ์ ์์ต๋๊น?
<Panel {...props}> ...
์๋ํ๊ธฐ ์์ํฉ๋๋ค.
๋๊ตฐ๊ฐ ์ด์ ๋ฅผ ์ค๋ช ํ ์ ์์ต๋๊น?
๋ด๊ฐ ์ดํดํ๋ฏ์ด ๋ถ๋ชจ Collapse๋ ํค๋, ํค ๋ฐ ์ถ๊ฐ (์๋ํ์ง ์๋ ์์์) ์ด์ธ์ ์ํ์ ์ค์ ํด์ผํฉ๋๋ค. ๋ถ๋ชจ Collapse์ ์ด๋ฌํ ์ํ์ ์ฌ์ฉ์ ์ ์ ๊ตฌ์ฑ ์์ ๋ด์ ํจ๋ ๊ตฌ์ฑ ์์์ ๋ช ์ ์ ์ผ๋ก ๋ฐฐ์นํด์ผํฉ๋๋ค.
React Inspector๋ฅผ ์ฌ์ฉํ์ฌ ๋ณ๊ฒฝํ๊ณ ํ๋์ฉ ์ ๋ฌํ ๊ฐ๋ฅํ ๋ชจ๋ ์ํ์ ๋ฐฐ์ธ ์ ์์ง๋ง ... props ๊ตฌ๋ฌธ์ ๋ถ๋ชจ๊ฐ ์์ ํจ๋์ ์ถ๊ฐํ๋ ค๋ ๋ชจ๋ ๊ฒ์ด ์ฒจ๋ถ๋๋๋กํฉ๋๋ค ( ๋ช ์ ์ ์ผ๋ก ์ค์ ํด์ผํ๋ ํญ๋ชฉ์ ํฌํจํ๋ ์ด์ ๊ตญํ๋์ง ์์)
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด์ผํฉ๋๋ค.
๋ง์ (๋๋ ๊ฑฐ์) ๊ฐ๋ฐ์๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉ์ ์ ์ ๊ตฌ์ฑ ์์์ ์ฌ์ฉํ๊ธฐ๋ฅผ ์ํฉ๋๋ค.
์)
์ด ์ฝ๋๋ ์๋ํ์ง ์์ต๋๋ค. ๋ฉ๋ด์ ๋ฉ๋ด ํญ๋ชฉ์๋ ๋ถํฌ๋ช
ํ ์ํ์ด ํ์ํ๊ธฐ ๋๋ฌธ์
๋๋ค.
<Menu>
{ menus.map((item) => {
if (item.to) {
return <Menu.Item title={item.title} />;
}
// some codes...
return null;
})}
</Menu>
ํธ์ ๋ด์ ๊ฐ๊ธฐ
์ค๋ ๋๋ฅผ ์ฝ์์ต๋๊น?
์๋ํ๊ฒํ๋ ค๋ฉด ๋๋จธ์ง ์ํ์ ๋ด๋ถ antd ๊ตฌ์ฑ ์์์ ์ ๋ฌํด์ผํฉ๋๋ค.
antd
Menu
๋ด๋ถ์์ antd
react-router
NavLinks
๋ํ ์ฌ์ฉ์ ์ง์ ๊ตฌ์ฑ ์์ + ์กฐ๊ฑด๋ถ ๋ ๋๋ง์ ์ป๋ ๋ฐ ๋์์ด ๋ ๊ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค react-router
์ค์ ๋ก ์ด๊ฒ์ ์์ ์ด ํ์ํฉ๋๋ค. ์ด ์ค๋ ๋๋ฅผ ์ฐพ๊ธฐ๊น์ง ๋ง์ ์๊ฐ์ด ๊ฑธ๋ฆฝ๋๋ค.
_edit- ์ ๊ฒฝ ์ฐ์ง ๋ง์ธ์, selectedKeys๊ฐ ์ ๋๋ก ์๋ํ์ง ์์ต๋๋ค _
const Nav = withRouter(() => {
const auth = store.isAuthenticated;
return (
<Menu selectedKeys={[history.location.pathname]} mode="horizontal">
<NavItem id="/">Home</NavItem>
{auth && <NavItem id="/create">Create Post</NavItem>}
{!auth && <NavItem id="/sign-in">Sign In</NavItem>}
{!auth && <NavItem id="/register">Register</NavItem>}
</Menu>
);
});
const NavItem = ({ ...props }) => (
<Menu.Item {...props} key={props.id}>
<NavLink exact to={props.id}>
{props.children}
</NavLink>
</Menu.Item>
);
ํธ์ ๋ด์ ๊ฐ๊ธฐ
์ค๋ ๋๋ฅผ ์ฝ์์ต๋๊น?
์๋ํ๊ฒํ๋ ค๋ฉด ๋๋จธ์ง ์ํ์ ๋ด๋ถ antd ๊ตฌ์ฑ ์์์ ์ ๋ฌํด์ผํฉ๋๋ค.
์์ ์๋ฅผ ์ดํด๋ณผ ์ ์์ต๋๊น? ์ด ์ค๋ ๋์์ ๋ชจ๋ ์์
์ ์ ์ฉํ๋ค๊ณ ์๊ฐํ์ง๋ง ์ฌ์ ํ ์ ๋๋ก ์๋ํ์ง ์์ต๋๋ค. props๋ฅผ ์๋๋ก ์ ๋ฌํ๊ณ Menu.Item
์ ํผ์นฉ๋๋ค.ํ์ง๋ง ํ์ฑํ๋๋ฉด ์ฌ์ ํ ๊ฐ์กฐ ํ์๋์ง ์์ผ๋ฉฐ ๊ตฌ์ฑ ์์ ํธ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๋๋ ๊ทธ ๋ฌธ์ ์ ์๊ฐ์ ๋ณด๋๋ค ...
๊ทธ๋ฆฌ๊ณ ๊ทธ๊ฒ์ ํ ์ ์์ต๋๋ค, ๋น์ ์ ie์ ๋๋จธ์ง ์ํ์ ์ ๋ฌํ๊ธฐ ๋งํ๋ฉด๋ฉ๋๋ค. Collapse.Panel (rc-panel์ ์์ค ์ฝ๋๋ฅผ ํ์ธํ์ฌ ์ดํด)
์ ๊ฒฝ์ฐ์๋ "{... props}"๋ค์ "header = {calculated_header}"๋ฅผ ๋ฃ์ด์ผํฉ๋๋ค. ์ด๋ ๊ฒํ์ง ์์ผ๋ฉด ํจ๋์ ํค๋๊ฐ ํ์๋์ง ์์ต๋๋ค. ์ํ์ค ๋ท๋ถ๋ถ์ ๋์ค๋ "{... props}"๊ฐ "ํค๋"์ ๋ณด๋ฅผ ๋ฎ์ด ์ฐ๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ฒ์์ "{... props}"๋ฅผ ๋ฃ์ผ๋ฉด ์๋ํฉ๋๋ค. ์ด ๊ฒฝ์ฐ ๋์ค์ ๋ํ๋๋ "ํค๋"๊ฐ ์ํ์ "ํค๋"์ ๋ณด๋ฅผ ๋ฎ์ด ์ฐ๋ ๊ฒ ๊ฐ์ต๋๋ค.
@ marcin-piela ์๋ต์ ๋ํ ๋์ ์ ์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
export const CustomPanel: React.FC = ({ headerinfo, children, ...props }) => {
// do whatever you like
const calculated_header = {() => headerinfo.someinformation }
return <Collapse.Panel {...props} header={calculated_header} >
{children}
</Collapse.Panel>
};
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
์ด ๋ฌธ์ ๋ ๋ฌธ์์์ ์ค์ ๋ก ์ธ๊ธ๋์ด์ผํฉ๋๋ค.์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ ์ดํดํ๊ธฐ ์ํด์ด ๋ฒ๊ทธ๋ฅผ ์กฐ์ฌํ๋ ๋ฐ ํ๋ฃจ ์ข ์ผ ๋ญ๋นํ์ต๋๋ค. ๋ค๋ฅธ ๊ฐ๋ฐ์๊ฐ ๋น์ ์ด ์ํฐ ํจํด์ ์ฌ์ฉํ๊ณ React ํค๋ฅผ ์ค๊ณํ๋ ๊ฒ์ ์์๋ด๋ ๋ฐ ๋๋ฌด ๋ง์ ์๊ฐ์ ๋ญ๋น ํ ํ์๊ฐ ์๋๋ก ๊ฒฝ๊ณ ๋ฅผ ํด์ฃผ์ธ์. ๊ทธ๋ฆฌ๊ณ ์ด์ ๋น์ ์ ์ปค๋ฎค๋ํฐ์์ ์ฌ์ฉํ ์์๋ ๋ง์ HOC ๋๋ ๋ฐ์ฝ๋ ์ดํฐ์ ๋งค์ฐ ์ทจ์ฝํฉ๋๋ค.
์ด๊ฒ์ ์ ๋ง ๋ถ๋๋ฌ์ด ์ผ์ ๋๋ค. ๋ค์ ๋ฉ์ด์ ๋ฒ์ ์์ ์์ ํ์๊ธฐ ๋ฐ๋๋๋ค.