🚗

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

2021/03/26に公開

はじめに

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

Discussion