skip to Main Content

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

Answers


  1. 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>;
    }
    
    Login or Signup to reply.
  2. 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;
            }
        });
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search