react-linkifyで一部のリンクをReact RouterのLinkで出力する
はじめに
react-linkifiyはテキスト内のリンクを解析し、有効なリンクに変換してくれるライブラリです。
基本的な使い方
解析したいテキストをLinkifyで囲みます。
<Linkify>
See source code at https://github.com/tasti/react-linkify/.
</Linkify>
たったこれだけでhttps://github.com/tasti/react-linkify/がリンクに変換されます。
実現したいこと
デフォルトの状態だと解析されたリンクは全てaタグで囲まれたリンクに変換されますが、それがサイト内のリンクでも遷移時にページがリロードされてしまいます。
これだとあまり良くないUXになってしまうため、サイト内のリンクをaタグの代わりにReact RouterのLinkでリンクを出力したくなりました。
実装
ソースコード
import React from 'react';
import { Link } from 'react-router-dom';
import Linkify from 'react-linkify';
// content: string (解析するテキスト)
const CustomLinkify = ({ content }) => {
const url = 'https://example.com';
// サイト内のリンクかどうか判定
const componentDecorator = (href, text, key) =>
!text.indexOf(url) ? (
<Link key={key} to={text.replace(url, '')}>
{text}
</Link>
) : (
<a key={key} href={href} target="_blank" rel="noopener noreferrer">
{text}
</a>
);
return <Linkify componentDecorator={componentDecorator}>{content}</Linkify>;
};
export default CustomLinkify;
今回はCustomLinkifyという名前でコンポーネントを作成してみました。
使い方
<CustomLinkify content={content} />
処理の流れ
componentDecorator関数の中を見ていきます。
!text.indexOf(url)
この条件式はtextがurlと前方一致(text.indexOf(url) === 0)の場合のみtrueになります。
参考にした記事はこちらです。
例えばhttps://example.com/やhttps://example.com/user1のような文字列はtrueになります。
<Link key={key} to={text.replace(url, '')}>
{text}
</Link>
あとはLinkのpath指定で不要なURLの部分を削除します。
(例: https://example.com/user1 -> /user1)
<a key={key} href={href} target="_blank" rel="noopener noreferrer">
{text}
</a>
aタグはこんな感じです。Reactでtarget="_blank"を指定する場合はrel="noopener noreferrer"も一緒に書かないと警告が出ます。
以上でサイト内のリンク(urlと前方一致のリンク)のみをLinkで出力できました。
さいごに
何か間違っている記述等あればご指摘いただけると嬉しいです。
Linkifyをカスタマイズする方法についてはこちらを参考にしました。
Discussion