react-linkifyで一部のリンクをReact RouterのLinkで出力する

公開日: 2021-08-06

更新日: 2021-08-07

  • Tech
  • React
  • Tips

はじめに

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でリンクを出力したくなりました。

実装

ソースコード

// CustomLinkify.js

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)

この条件式はtexturlと前方一致(text.indexOf(url) === 0)の場合のみtrueになります。

参考にした記事はこちらです。
https://qiita.com/aqril_1132/items/9f69575bfbcf24bdf7b5

例えば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をカスタマイズする方法についてはこちらを参考にしました。
https://github.com/tasti/react-linkify/pull/51#issuecomment-355787057

yona

yona

琉球大学の理学部に所属している大学3年生です。 趣味と仕事でWebアプリ開発やシステム開発をしています。