Wrap Multiple Lines in React HTML

I am creating an object marker so that I can load a text file, view the contents on the screen, and then select the words that are in the array. This array is populated by the user when they manually highlight the selection, for example ...

const entities = ['John Smith', 'Apple', 'some other word'];

This is my text document that is displayed on the screen. It contains a lot of text, and some of this text needs to be visually highlighted to the user once they manually highlight some text, like the name John Smith, Apple and some other word

Now I want to visually highlight all instances of the object in the text, packing it into some markup, and doing something like this works fine:

getFormattedText() {
    const paragraphs = this.props.text.split(/\n/);
    const { entities } = this.props;

    return paragraphs.map((p) => {
        let entityWrapped = p;

        entities.forEach((text) => {
        const re = new RegExp(`${text}`, 'g');
        entityWrapped =
            entityWrapped.replace(re, `<em>${text}</em>`);
        });

        return `<p>${entityWrapped}</p>`;
    }).toString().replace(/<\/p>,/g, '</p>');
}

... however (!), it just gives me a big line, so I have to dangerously set the internal HTML, and therefore I cannot then attach the onClick event "React Method" to any of these selected objects, which I have to do.

The real way to do this is to return an array that looks something like this:

['This is my text document that is displayed on the screen. It contains a lot of text, and some of this text needs to be visually highlighted to the user, like the name', {}, {}, {}] {} - React, JSX.

, , , , , .

, ... ? , , . , React SetInnerHTML, , DOM?

Update

@AndriciCezar , , , , ( > 100), ( > 100kb). 10 , V .

- , , React ? SetInnerHTML ?

+6
3

, . , , , .

import React from 'react';

const input = 'This is a test. And this is another test.';
const keywords = ['this', 'another test'];

export default class Highlighter extends React.PureComponent {
    highlight(input, regexes) {
        if (!regexes.length) {
            return input;
        }
        let split = input.split(regexes[0]);
        // Only needed if matches are case insensitive and we need to preserve the
        // case of the original match
        let replacements = input.match(regexes[0]);
        let result = [];
        for (let i = 0; i < split.length - 1; i++) {
            result.push(this.highlight(split[i], regexes.slice(1)));
            result.push(<em>{replacements[i]}</em>);
        }
        result.push(this.highlight(split[split.length - 1], regexes.slice(1)));
        return result;
    }
    render() {
        let regexes = keywords.map(word => new RegExp(`\\b${word}\\b`, 'ig'));
        return (
            <div>
                { this.highlight(input, regexes) }
            </div>);
    }
}
+4

- ?

- * . 22 273 (121,104 ) 3 44 .

!!! : , . , .

320 500 , . - . 10 , .

JS : https://jsfiddle.net/69z2wepo/79047/

const Term = ({ children }) => (
  <em style={{backgroundColor: "red"}} onClick={() => alert(children)}>
    {children}
  </em>
);

const Paragraph = ({ paragraph, keywords }) => {
  let keyCount = 0;
  console.time("Measure paragraph");

  let myregex = keywords.join('\\b|\\b');
  let splits = paragraph.split(new RegExp(`\\b${myregex}\\b`, 'ig'));
  let matches = paragraph.match(new RegExp(`\\b${myregex}\\b`, 'ig'));
  let result = [];

  for (let i = 0; i < splits.length; ++i) {
    result.push(splits[i]);
    if (i < splits.length - 1)
      result.push(<Term key={++keyCount}>{matches[i]}</Term>);
  }

  console.timeEnd("Measure paragraph");

  return (
    <p>{result}</p>
  );
};


const FormattedText = ({ paragraphs, keywords }) => {
    console.time("Measure");

    const result = paragraphs.map((paragraph, index) =>
      <Paragraph key={index} paragraph={paragraph} keywords={keywords} /> );

    console.timeEnd("Measure");
    return (
      <div>
        {result}
      </div>
    );
};

const paragraphs = ["Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ornare tellus scelerisque nunc feugiat, sed posuere enim congue. Vestibulum efficitur, erat sit amet aliquam lacinia, urna lorem vehicula lectus, sit amet ullamcorper ex metus vitae mi. Sed ullamcorper varius congue. Morbi sollicitudin est magna. Pellentesque sodales interdum convallis. Vivamus urna lectus, porta eget elit in, laoreet feugiat augue. Quisque dignissim sed sapien quis sollicitudin. Curabitur vehicula, ex eu tincidunt condimentum, sapien elit consequat enim, at suscipit massa velit quis nibh. Suspendisse et ipsum in sem fermentum gravida. Nulla facilisi. Vestibulum nisl augue, efficitur sit amet dapibus nec, convallis nec velit. Nunc accumsan odio eu elit pretium, quis consectetur lacus varius"];
const keywords = ["Lorem Ipsum"];

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      limitParagraphs: 10
    };
  }

  componentDidMount() {
    setTimeout(
      () =>
        this.setState({
          limitParagraphs: 200
        }),
      1000
    );
  }

  render() {
    return (
      <FormattedText paragraphs={paragraphs.slice(0, this.state.limitParagraphs)} keywords={keywords} />
    );
  }
}

ReactDOM.render(
  <App />, 
  document.getElementById("root"));
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root">
</div>
Hide result
+5

, , .

const words = paragraph.split( ' ' );

<span>. onDoubleClick .

return (
  <div>
    {
      words.map( ( word ) => {
        return (
          <span key={ uuid() }
                onDoubleClick={ () => this.highlightSelected() }>
                {
                  this.checkHighlighted( word ) ?
                  <em>{ word } </em>
                  :
                  <span>{ word } </span>
                }
          </span>
        )
      })
    }
  </div>
);

, , this.highlightSelected(), , , .

highlightSelected() {

    const selected = window.getSelection();
    const { data } = selected.baseNode;

    const formattedWord = this.formatWord( word );
    let { entities } = this.state;

    if( entities.indexOf( formattedWord ) !== -1 ) {
      entities = entities.filter( ( entity ) => {
        return entity !== formattedWord;
      });
    } else {
      entities.push( formattedWord );
    }  

    this.setState({ entities: entities });
}

, , , . checkHighlighted() , .

checkHighlighted( word ) {

    const formattedWord = this.formatWord( word );

    if( this.state.entities.indexOf( formattedWord ) !== -1 ) {
      return true;
    }
    return false;
  }

And finally, the function formatWord()simply removes any periods or commas and does everything in lower case.

formatWord( word ) {
    return word.replace(/([a-z]+)[.,]/ig, '$1').toLowerCase();
}

Hope this helps!

+2
source

Source: https://habr.com/ru/post/1017196/


All Articles