Drawerを作るときに考えられる要素としては下記になります。
- Drawerを開くときのボタン
- Drawerを閉じるときのDrawerの中のボタン
- Drawerの中身
- containerの上に重なるalphaかかったが黒レイヤー
この要素のなかで、Drawerが開いているかどうかを判定する処理と開閉する際のイベント処理をするComponentと、Drawerの中身をただ愚直に書くだけのcomponentとを分けたいと思います。そのほうがコードの見通しがよくなると思うので。
書いてみた
- Material-uiを使用
Sanple.tsx(Drawerトリガーのボタン)
- Drawerを開く処理を行うボタンを配置
- reducerを通してDrawerを開く
Sample.tsx
<Button
variant="contained"
color="primary"
type="button"
onClick={sideMenu(true)}>
Drawer
</Button>
<DrawerWrapper component={<Drawer />} />
イベント処理をするComponent
- propsのcomponentはDrawerの中身をただ愚直に書くだけのcomponent。そのcomponentにReact.cloneElementでDrawerを閉じるevent処理と開閉判定のbooleanをpropsとして渡しています
- 開閉判定はreducerから取得しています
DrawerWrapper.tsx
export interface ImplProps {
closeSideMenu?: () => void;
isSideMenu?: boolean;
}
interface ImplInnerProps {
sideMenuAction: (arg1: boolean) => void;
isSideMenu: boolean;
}
interface ImplOuterProps {
component: ReactElement;
}
export type TypeDrawerWrapper = ImplInnerProps & ImplOuterProps;
const DrawerWrapper: FC<TypeDrawerWrapper> = props => {
const { component, isSideMenu, sideMenuAction } = props;
const closeSideMenu = useCallback(() => {
sideMenuAction(false);
}, [sideMenuAction]);
return React.cloneElement(component, { isSideMenu, closeSideMenu });
};
const mapStateToProps = (state: ImplState) => ({
isSideMenu: state.animatio.isSideMenu
});
const enhance = compose<TypeDrawerWrapper, ImplOuterProps>(
connect(mapStateToProps, {
sideMenuAction,
})
);
const Drawer = enhance(DrawerWrapper);
export default Drawer;
composeの型定義は下記
compose<propsで設定したcomponentのprops, このcomponent自体のprops>
中身をコーディングするComponent
- propsは
DrawerWrapper.tsx
のReact.cloneElementで設定したpropsです - その取得したpropsを元に表示画面を制作してます
- 背景をClickするとDrawerが閉じます
- CloseボタンをClickするとDrawerが閉じます
Drawer.tsx
const Drawer: FC<ImplProps> = props => {
const { isSideMenu, closeSideMenu } = props;
return (
<div>
<DrawerBg onClick={closeSideMenu} isSideMenu={isSideMenu} />
<DrawerInner isSideMenu={isSideMenu}>
<Button
variant="outlined"
color="secondary"
type="button"
onClick={closeSideMenu}>
Close
</Button>
<ul>
<li>犬</li>
<li>猫</li>
<li>鳥</li>
</ul>
</DrawerInner>
</div>
);
};
export default Drawer;
以上になります。
event処理とReducerからstateを取得する処理のcomponentと、画面表示だけのcomponentを分けて制作してみました。