How to wrap hashtag and @username with next Link?

515 Views Asked by At

I am working on an application where users can create posts and can mention other users and use the #hashtag in the post. Through API call I get the list of post, now the question is how can we wrap hashtags and usernames with next.js Link component so that on clicking on these link user can be navigated to different pages without page refresh.

I am able to wrap this with <a> tag and render the text with dangerouslySetInnerHTML. But this way my page will get refreshed by clicking on the link I don't want off course this behavior.

Here's my code to format the text with <a> tag:

export const formatPostText = (text) => {
    let splitText = text.split(' ')
    splitText.forEach((word, index) => {
        if (word[0] === "@") {
            splitText[index] = '<a class="text-cyanBlue" href="/' + word.replace('@', '') + '/in' + '">' + word + '</a>'
        } else if (word[0] === "#") {
            splitText[index] = '<a class="text-cyanBlue" href="hashtag' + '/' + word.replace('#', '') + '">' + word + '</a>'
        }
    })
    return splitText.join(' ')
}

I do want the same behavior as LinkedIn and Facebook has done it.

Approach: One way I can think of is to use React.createElement but I doubt this is gonna work.

Thanks in advance!!

2

There are 2 best solutions below

0
AudioBubble On BEST ANSWER

I implemented similar things in a recent project. I hope this might be helpful.

export const formatText = (text) => {
    console.log("text", text)
    let content = text.split(/((?:#|@|https?:\/\/[^\s]+)[a-zA-Z]+)/);
    let hashtag;
    let username;
    return content.map((word) => {
        if (word.startsWith("#")) {
            hashtag = word.replace('#', '')
            return <Link href={`/hashtag/${hashtag}`}><a
                className="text-cyanBlue/80 hover:text-cyanBlue">{word}</a></Link>;
        } else if (word.startsWith("@")) {
            username = word.replace('@', '')
            return <Link href={`/profile/${username}`}><a
                className="text-cyanBlue/80 hover:text-cyanBlue">{word}</a></Link>;
        } else if (word.includes("http")) {
            return <a target="_blank" href={word} className="text-cyanBlue/80 hover:text-cyanBlue">{word}</a>
        } else {
            return word;
        }
    });
}
1
Konrad On

I used spans with colors here to make example clear: https://codesandbox.io/s/modest-http-wnp5xq?file=/src/App.js

export default function App() {
  const string =
    "Hello everyone, me and @ritika are going to be married this month #happy, #marriage";

  const getJSX = () => {
    // split with capture
    const parts = string.split(/((?:#|@)[a-zA-Z]+)/).filter((s) => s.length);
    return parts.map((part) => {
      if (part.startsWith("@")) {
        // if part starts with `@` return `Link` in your case
        return <span style={{ color: "red" }}>{part}</span>;
      } else if (part.startsWith("#")) {
        // if part starts with `#` return other `Link`
        return <span style={{ color: "green" }}>{part}</span>;
      } else {
        // just return string as is
        return part;
      }
    });
  };

  return <div className="App">{getJSX()}</div>;
}