简体   繁体   中英

Javascript/react - highlight matching parenthesis

today I faced a problem with highlighting matching parenthesis in React. This is example text:

(my text (is here and) I want (to highlight (something here)))

And I want it to look like in code editor, I mean: image attached

I tried to use react-process-string :

 processString([ { regex: /\\(|\\)/g, fn: (key, result) => this.colorBracket(key, result[0]) } ])(value); colorBracket = (key, result) => { const { usedColors } = this.state; const bracketColors = ['red', 'green', 'yellow', 'blue', 'purple']; let newColor = ''; if (result === '(') { newColor = usedColors.length ? bracketColors[usedColors.length] : bracketColors[0]; if (!usedColors.includes(newColor)) { this.setState({ usedColors: [...usedColors, newColor] }); } } else { newColor = usedColors.length ? usedColors[usedColors.length - 1] : bracketColors[0]; if (usedColors.length) { this.setState({ usedColors: usedColors.filter(e => e !== newColor) }); } } return <span style={{ color: newColor }}>{result}</span>; };

but I faced problem with react maximum update depth .

Is it possible to do it more simple, without updating state and so on?

Sure thing, it's not really hard at all once you know the right tools.

Here's a CodeSandbox example I whipped up, and a snippet of the same below (slightly adjusted for Stack Overflow's ancient Babel version).

The idea is:

  • use string.split 's regexp mode to split the string into fragments that are either brackets or aren't
  • iterate over those fragments to keep track of the nesting level for the brackets (to properly colorize pairs)
  • finally, return a React fragment with those children (this way we don't have to deal with array keys)

The colors in this example are only 3 levels deep, but you could easily add more, or make the colorization loop over N colors using the modulus operator.

 function BracketHighlighter({ text }) { const children = React.useMemo(() => { const out = []; let level = 0; text.split(/([()])/).forEach((bit) => { if (bit === "(") { level++; out.push(<span className={"l" + level}>{bit}</span>); } else if (bit === ")") { out.push(<span className={"l" + level}>{bit}</span>); level--; } else { out.push(bit); } }); return out; }, [text]); return React.createElement(React.Fragment, {}, ...children); } function App() { const [text, setText] = React.useState( "(my text (is here and) I want (to highlight (something here)))" ); return ( <div className="App"> <input value={text} onChange={(e) => setText(e.target.value)} /> <br /> <BracketHighlighter text={text} /> </div> ); } ReactDOM.render(<App />, document.getElementById("root"));
 .l1 { background-color: orange; } .l2 { background-color: lightgreen; } .l3 { background-color: cyan; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script> <div id="root"></div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM