0

I have this array of objects. I want to style only a specific word like the date 2014 in short story object. I'm rendering this array in jsx

id:1,
img: coderIMG ,
BlogTitle:"My first encounter with web development in 2014",
shortStory:`back in late 2014 when i was 15 years old , i was passionate about`,
  • You'd need to search and replace then use a React HTML rendering library (if you want to mark it up w/ HTML) or you could mark it up as Markdown/etc and use a Markdown library. – Dave Newton Feb 22 '23 at 15:03

1 Answers1

0

You would have to split the text up and wrap dates in a <span> with a className.

In the example below, I created a component called <FormattedShortStory /> that takes a className, pattern, and text. It handles splitting-up the text and wrapping each token.

Edit

The pattern needs to be a string or RegExp:

Note: The curly braces are required, if the pattern is a literal string.

// Valid
<FormattedShortStory
  className="date"
  pattern={"\\d{4}"}
  text={shortStory} />

// Valid
<FormattedShortStory
  className="date"
  pattern={/\d{4}/g}
  text={shortStory} />

// Invalid
<FormattedShortStory
  className="date"
  pattern="\\d{4}"
  text={shortStory} />

const { useEffect, useState } = React;

/*
 * Ensures that the provided pattern is either a string or RegExp
 * @param {string|RegExp} pattern - a regular expression pattern
 * @returns {RegExp} - converts string to a RegExp or returns the pattern
 * @throws Error
 */
const guardRegex = (pattern) => {
  if (pattern instanceof RegExp) return pattern;
  if (typeof pattern === 'string') return new RegExp(pattern, 'g');
  throw new Error('pattern is neither a RegExp or string');
}

/*
 * Tokenizes a string by a delimiter.
 * Inspired by:
 * - https://stackoverflow.com/a/17414844/1762224
 * - https://docs.oracle.com/javase/8/docs/api/java/util/StringTokenizer.html
 * @param {string} str - a string to be parsed
 * @param {string|RegExp} delim - the delimiters
 * @param {boolean} [returnDelims=false] - whether to return the delimiters as tokens
 * @returns {string[]} - list of tokens
 */
const stringTokenizer = (str, delim, returnDelims = false) => {
  const regex = guardRegex(delim), result = [];
  let token, index;
  while (str !== '') {
    regex.lastIndex = 0;
    token = regex.exec(str);
    if (token === null) { break; }
    index = token.index;
    if (token[0].length === 0) { index = 1; }
    result.push(str.substr(0, index));
    if (returnDelims) {
      result.push(token[0]);
    }
    index = index + token[0].length;
    str = str.slice(index);
  }
  result.push(str);
  return result;
}

const FormattedShortStory = ({ className, pattern, text }) => (
  <p>
    {stringTokenizer(text, pattern, true).map((token, index) =>
      guardRegex(pattern).exec(token)
        ? <span key={token + index} className={className}>{token}</span>
        : token
    )}
  </p>
);

const getData = () => Promise.resolve([{
  id: 1,
  BlogTitle: 'My first encounter with web development in 2014',
  shortStory: 'Back in late 2014 when I was 15 years old, I was passionate about...',
}]);

const App = () => {
  const [data, setData] = useState([]);

  useEffect(() => { getData().then(setData); }, []);

  return (
    <div>
      <h1>Blogs</h1>
      {data.map(({ id, BlogTitle, shortStory }) => (
        <div key={id}>
          <h2>{BlogTitle}</h2>
          <FormattedShortStory
            className="date"
            pattern={"\\d{4}"}
            text={shortStory}
          />
        </div>
      ))}
    </div>
  );
};

ReactDOM
  .createRoot(document.getElementById("root"))
  .render(<App />);
.date { color: red; font-weight: bold; }
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132