Заменить часть строки тегом в JSX
Я пытаюсь заменить части строки тегами JSX, например:
render: function() {
result = this.props.text.replace(":",<div className="spacer"></div>);
return (
<div>
{result}
<div>
);
}
Но, учитывая, что this.props.text
есть Lorem : ipsum
, это приводит к
<div>
Lorem [object Object] ipsum.
</div>
Есть ли способ решить тот или иной способ замены частей строки тегами JSX?
Ответы
Ответ 1
Когда вы передаете элемент JSX в replace()
в качестве второго аргумента, этот элемент преобразуется в строку, потому что replace()
ожидает строку в качестве второго аргумента. Что вам нужно сделать, это преобразовать вашу строку в массив строк и элементов JSX. Поэтому ваша переменная result
должна содержать что-то вроде ['Lorem ', <div className="spacer"></div>, ' ipsum']
.
Что-то вроде этого:
function flatMap(array, fn) {
var result = [];
for (var i = 0; i < array.length; i++) {
var mapping = fn(array[i]);
result = result.concat(mapping);
}
return result;
}
var Comp = React.createClass({
render: function () {
var result = 'Lorem : ipsum';
result = flatMap(result.split(':'), function (part) {
return [part, <div>spacer</div>];
});
// Remove the last spacer
result.pop();
return (
<div>
{result}
</div>
);
}
});
Ответ 2
Следующее также должно работать (предполагается ES6). Единственный нюанс заключается в том, что текст фактически завернут внутри элемента DIV и не предшествует ему, предполагая, что вы собираетесь использовать CSS для фактического интервала, это не должно быть проблема.
const result = this.props.text.split(':').map(t => {
return <div className='textItem'>{t}</div>;
});
Ответ 3
Принятый ответ - два года. Для этой проблемы была создана проблема # 3368, и на основе решения, предоставленного сотрудником Facebook, работающим над React, была создана реагирующая строка-замена.
Используя ответную строку, вот как вы можете решить вашу проблему
const reactStringReplace = require('react-string-replace');
const HighlightNumbers = React.createClass({
render() {
const content = 'Hey my number is 555:555:5555.';
return (
<span>
{reactStringReplace(content, ':', (match, i) => (
<div className="spacer"></div>
))}
</span>
);
},
});
Ответ 4
У меня была более распространенная задача - обернуть все (английские) слова пользовательским тегом.
Мое решение:
class WrapWords extends React.Component {
render() {
const text = this.props.text;
const isEnglishWord = /\b([-'a-z]+)\b/ig;
const CustomWordTag = 'word';
const byWords = text.split(isEnglishWord);
return (
<div>
{
byWords.map(word => {
if (word.match(isEnglishWord)) {
return <CustomWordTag>{word}</CustomWordTag>;
}
return word;
})
}
</div>
);
}
}
// Render it
ReactDOM.render(
<WrapWords text="Argentina, were playing: England in the quarter-finals (the 1986 World Cup in Mexico). In the 52nd minute the Argentinian captain, Diego Maradona, scored a goal." />,
document.getElementById("react")
);
<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="react"></div>
Ответ 5
После некоторых исследований я обнаружил, что существующие библиотеки не соответствуют моим требованиям. Поэтому, конечно, я написал свое собственное:
https://github.com/EfogDev/react-process-string
Он очень прост в использовании. Пример вашего примера:
let result = processString({
regex: /:/gim,
fn: () => <div className="spacer"></div>
})(this.props.test);
Ответ 6
Если вы также захотите сделать замены в рамках замены (например, чтобы выделить условия поиска в URL-адресах), проверьте этот модуль node, который я создал - https://github.com/marcellosachs/react-string-replace-recursively
Ответ 7
Пример с крючками:
import React, { useEffect, useState, useRef } from 'react'
export function Highlight({ value, highlightText }) {
const [result, resultSet] = useState(wrap())
const isFirstRun = useRef(true)
function wrap() {
let reg = new RegExp('(' + highlightText + ')', 'gi')
let parts = value.split(reg)
for (let i = 1; i < parts.length; i += 2) {
parts[i] = (
<span className='highlight' key={i}>
{parts[i]}
</span>
)
}
return <div>{parts}</div>
}
useEffect(() => {
//skip first run
if (isFirstRun.current) {
isFirstRun.current = false
return
}
resultSet(wrap())
}, [value, highlightText])
return result
}
Ответ 8
Написал служебную функцию для jsx.
const wrapTags = (text: string, regex: RegExp, className?: string) => {
const textArray = text.split(regex);
return textArray.map(str => {
if (regex.test(str)) {
return <span className={className}>{str}</span>;
}
return str;
});
};
Ответ 9
Я пришел к следующему простому решению, которое не включает стороннюю библиотеку или регулярные выражения, возможно, оно все еще может кому-то помочь.
В основном просто используйте .replace() для замены строки обычным html, записанным в виде строки, например:
text.replace('string-to-replace', '<span class="something"></span>')
А затем визуализировать его, используя dangerouslySetInnerHTML
внутри элемента.
Полный пример:
const textToRepace = 'Insert :' // we will replace : with div spacer
const content = textToRepace.replace(':', '<div class="spacer"></div>') : ''
// then in rendering just use dangerouslySetInnerHTML
render() {
return(
<div dangerouslySetInnerHTML={{
__html: content
}} />
)
}