[React Bootstrap] Overlays を表示してみる | 心を無にして始める React
今回は、Overlay コンポーネントを表示します。
準備
まだ components フォルダがなければ作ります。
src
を右クリックして New Folder
。
components と入力してフォルダを作ります。
今回は、components フォルダに Overlay のコンポーネントを作って、表示してみます。
公式のドキュメントはここ。
https://react-bootstrap.github.io/components/overlays/#overlay
Overlay コンポーネントをつくる
component フォルダに Overlay.js
を作ります。
Overlay.js
を心を無にして編集してみます。
import React from 'react';
import { Overlay as BootstrapOverlay } from 'react-bootstrap';
const Overlay = React.forwardRef(({
children,
...otherProps
}, ref) => {
return (
<BootstrapOverlay ref={ref} {...otherProps}>
<div className="position-absolute">
{children}
</div>
</BootstrapOverlay>
)
})
export default Overlay;
プロジェクトでは、コンポーネントを統一したデザインで利用することが多いです。
そのため、(React Bootstrap のコンポーネントをその場その場でカスタマイズしながら使うよりも、)プロジェクトでコンポーネントにしたものを使うほうが、変更をお手軽に漏れなくできることが多いです。
さらに、Overlay コンポーネントでは ref を使うため、 Button.js
が ref を受け取れるように直しておきます。
// React.forwordRef を使います。
import React, { useEffect, useState } from 'react';
import {
Button as BootstrapButton,
Spinner,
} from 'react-bootstrap';
const Button = React.forwardRef(({
children,
onClick,
...otherProps
}, ref) => {
const [isLoading, setLoading] = useState(false);
const handleClick = () => {
if (onClick) {
setLoading(true);
}
}
const cb = () => {
setLoading(false);
}
useEffect(() => {
if (isLoading) {
onClick(cb);
}
}, [isLoading, onClick]);
return (
<BootstrapButton
ref={ref}
onClick={handleClick}
{...otherProps}
disabled={isLoading}
>
{isLoading ? <Spinner animation="border" size="sm" /> : children}
</BootstrapButton>
)
});
export default Button;
Overlay コンポーネントを表示する
それでは、 App.js
を編集して Overlay コンポーネントを表示します。
import React, { useRef, useState } from 'react';
import './App.css';
import Overlay from './components/Overlay';
import Button from './components/Button';
const PLACEMENTS = ['top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start'];
function App() {
const [show, setShow] = useState(false);
const target = useRef(null);
return (
<>
<div className="p-5 bg-dark">
<div className="p-5 d-flex flex-column justify-content-center align-items-center h-100">
<Button
ref={target}
variant="light"
style={{ width: 512, height: 384 }}
onClick={cb => {
setShow(!show);
cb();
}}
>
<h1>BASE</h1>
</Button>
</div>
</div>
{
PLACEMENTS.map(placement => {
return (
<Overlay target={target.current} show={show} placement={placement}>
<div className="p-3 bg-danger text-light text-center rounded" style={{ width: 128 }}>
{placement}
</div>
</Overlay>
);
})
}
</>
);
}
export default App;
画面を確認してみます。
はい、できました。