やりたいこと
- webアプリで、画像をモーダルで表示したい!
- そのモーダルにSNSシェアボタンを設置したい
- そのモーダルからSNSにシェアすると、その画像がOGPで表示されるようにしたい!
- ただし、アプリ連携はさせたくない
実装
大まかな説明
- モーダルを作成
-
material-uiのモーダルを使う
- 注意1:
open
は常にtrue
にしておく - 注意2:
onClose
ではリダイレクトの関数を実施する
- 注意1:
- モーダルの中に
react-share
の好きなコンポーネントを置く
-
material-uiのモーダルを使う
-
react-helmet
でmetaタグを設定する- metaタグ設定のコードは、モーダルの横に設置する
-
react-router
でルーティングする(※URLとOGPは1:1対応なので、ルーティングは必須)-
ネストされたルーティングを参考にする
- 注意:
/
配下に直接:hogehoge
を指定することはできない
- 注意:
-
ネストされたルーティングを参考にする
- Netlifyでホスティングする(※自前でprerenderingすれば他のホスティングサービスでも可)
-
Netlifyのpre-renderingによりSPAでもreact-helmetが機能する
- 注意1:
public
ディレクトリ配下に_redirects
ファイルを設置しないとreact-routerがうまく動かず、URLが機能しない - 注意2:pre-renderingの設定をし忘れない
- 注意3:ビルドの結果出力されるディレクトリの指定を間違えると、ビルドは成功しても何も表示されない
- 注意1:
-
Netlifyのpre-renderingによりSPAでもreact-helmetが機能する
ライブラリなどのバージョン
バージョンが異なるとコードや動作が異なる場合があります。
- node v13.11.0
- react v16.13.1
- @material-ui/core v4.9.12
- react-router-dom v5.1.2
- react-share v4.1.0
- react-helmet v6.0.0
コード
src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import * as serviceWorker from './serviceWorker';
import {
BrowserRouter as Router,
Switch,
Route,
} from "react-router-dom";
import Lives from './components/Lives';
ReactDOM.render(
<React.StrictMode>
<Router>
<Switch>
<Route exact path="/">
<App />
</Route>
<Route path="/lives">
<Lives />
</Route>
</Switch>
</Router>
</React.StrictMode>,
document.getElementById('root')
);
serviceWorker.unregister();
src/components/Lives.tsx
import React from 'react';
import { useRouteMatch, Link, Switch, Route } from 'react-router-dom';
import { Button } from '@material-ui/core';
import YourModal from './YourModal';
export default function Lives() {
let { path, url } = useRouteMatch()
return (
<div>
<Switch>
<Route path={`${path}/:liveId`}>
<YourModal />
</Route>
</Switch>
<Link to={`${url}/xxxxxxxxxx`}>
<Button variant="contained">Open Modal</Button>
</Link>
</div>
)
}
src/components/YourModal.tsx
import React from 'react';
import { useLocation, useHistory } from 'react-router-dom';
import { Helmet } from 'react-helmet';
import { Modal } from '@material-ui/core';
import { TwitterShareButton, TwitterIcon } from 'react-share';
export default function YourModal() {
const baseUrl = "http://example.com"
const currentUrl: string = baseUrl + useLocation().pathname
const imgUrl = "https://source.unsplash.com/random"
const history = useHistory()
const handleClose = () => {
history.push("/lives")
}
return (
<div>
<Helmet
title={`Lives&Lives`}
meta={[
{ name: 'twitter:card', content: 'summary_large_image' },
{ name: 'twitter:site', content: '@IkkoKojima' },
{ name: 'twitter:creator', content: '@IkkoKojima' },
{ property: 'og:title', content: 'Lives&Lives' },
{ property: 'og:type', content: 'website' },
{ property: 'og:url', content: currentUrl },
{ property: 'og:image', content: imgUrl },
{ property: 'og:description', content: '動物たちのイキイキとした姿をみんなで観察' },
]}
/>
<Modal
open={true}
onClose={handleClose}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<div style={{ background: 'white' }}>
<img src={imgUrl} alt="alt-text" style={{ width: "600px" }} />
<TwitterShareButton url={currentUrl} >
<TwitterIcon round />
</TwitterShareButton>
</div>
</Modal>
</div>
)
}
public/_redirects
/* /index.html 200
OGP動作確認
この辺が使える。デプロイした後しか動作しないので注意。
最後に
自分用の備忘録として作成したのですごく雑で申し訳ない。なにぶん、数時間ハマった後なので疲れているのです...
不明点や記述のミスなどありましたら、コメントくださいmm