๋ถ๋ช ํ ์๋ํ์ง ์๋์ด ์ฝ๋๊ฐ ์์ต๋๋ค.
_.each(matches, (match) ->
string = string.replace(match, ->
<span className="match" key={i++}>{match}</span>
)
)
๊ทธ ๊ฒฐ๊ณผ ๊ฐ์ฒด์ ํผํฉ๋ ๋ฌธ์์ด์ด ์์ฑ๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋์ ๋ด๊ฐ ์์. ํ์ง๋ง ์ด๋ป๊ฒ ๋ฌธ์์ด ์์ React ์ปดํฌ๋ํธ๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๊น? ๋ด๊ฐ ์ํ๋ ๊ฒ์ ๋ฐ์ ๊ตฌ์ฑ ์์๋ก ๋ฌธ์์ด์ ์ผ๋ถ๋ฅผ ๊ฐ์กฐ ํ์ํ๋ ๊ฒ์ ๋๋ค. ๊นจ์ง๊ธฐ ํ๋ ์ผ์ด์ค์ธ ๊ฒ ๊ฐ์์.
๋ค์๊ณผ ๊ฐ์ด ์๋ํด์ผ ํฉ๋๋ค.
const escapeRE = new RegExp(/([.*+?^=!:$(){}|[\]\/\\])/g)
const safeRE = (string) => {
return string.replace(escapeRE, "\\$1")
}
class Hightlight extends Component {
static propTypes = {
match : PropTypes.string,
string : PropTypes.string,
}
render() {
return (
<span
dangerouslySetInnerHTML={{
__html : string.replace(safeRE(this.props.match), "<strong className\"match\">$1</strong>")
}} />
)
}
}
์, dangerouslySetInnerHTML
์ ๋จ์ฉํ ์๊ฐ์ ํ์ง๋ง ์ด ์์ด๋์ด๊ฐ ๋ง์์ ๋ค์ง ์์ต๋๋ค. ์ด ๋ฐฉ๋ฒ์ ํฉ๋นํ ์ด์ ๋ก ์ํํ ๊ฒ์ผ๋ก ๋ถ๋ฅ๋์์ต๋๋ค.
๋ฌธ์์ด ๋ด์์ jsx๋ฅผ ๊ตฌ๋ฌธ ๋ถ์ํ๋๋ก React๋ฅผ ๊ฐ๋ฅด์น ๋ฐฉ๋ฒ์ด ์๋์? React๊ฐ iE๋ฅผ ๊ตฌ๋ฌธ ๋ถ์ํ๋๋ก ํ์ญ์์ค.
var example = "this one word <span className="match" key={i++}>hello</span> is highlighted"
๊ทธ๋ฆฌ๊ณ ์ด๊ฒ์ ๋ ๋ ๋ฉ์๋์์ ๋ฐํํ์๊ฒ ์ต๋๊น?
@binarykitchen React ์์๋ฅผ ๋์ ์ผ๋ก ๊ตฌ์ฑํ ์ ์์ผ๋ฉฐ ์ฌ๊ธฐ์์ ์ํํด์ผ ํ๋ ์์ ์ ๋๋ค. ๋ฌธ์์ด ๊ต์ฒด๋ง์ผ๋ก๋ ์ํํ ์ ์์ต๋๋ค.
@syranide ์, ์ด๋ฏธ ์๊ณ ์์ต๋๋ค. ์ ์์ ์: ์ด๊ฒ์ด ์ข์ JSX/React ๊ธฐ๋ฅ์ด ์๋๊น์? ๋ฌธ์์ด์ ๊ตฌ๋ฌธ ๋ถ์ํ๊ณ ๋ด๋ถ์ ๋ชจ๋ ํ๊ทธ๋ฅผ ์์ React ๊ตฌ์ฑ ์์๋ก ๋ฐ๊ฟ๋๋ค.
split
ํจ์๋ฅผ ์ ๊ท์๊ณผ ํจ๊ป ์ฌ์ฉํ๊ณ ๋ค์๊ณผ ๊ฐ์ด ์บก์ฒ๋ ๋ถ๋ถ์ ๋ฐ๊ฟ ์ ์์ต๋๋ค.
var parts = "I am a cow; cows say moo. MOOOOO.".split(/(\bmoo+\b)/gi);
for (var i = 1; i < parts.length; i += 2) {
parts[i] = <span className="match" key={i}>{parts[i]}</span>;
}
return <div>{parts}</div>;
๋ถ๋ถ๋ช ํ ๊ฒฝ์ฐ ์๋ ค์ฃผ์ญ์์ค.
๋ฐํ์์ JSX๋ฅผ ๊ตฌ๋ฌธ ๋ถ์ํ๋ ๊ฒ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ธฐ ์ฝ๊ณ ๋๋ฆฌ๋ฉฐ ๋ณด์์ ์ํฅ์ ๋ฏธ์น๊ธฐ ์ฝ์ต๋๋ค. ๋ณธ์ง์ ์ผ๋ก ์ํํ๊ฒ SetInnerHTML๋ณด๋ค ์์ ํ์ง ์์ ๊ฒ์ ๋๋ค.
๊ทธ๊ฒ์ ์ ํ ์ผ์ด์ค์ ์ฝ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ ์ ์์ต๋๋ค.
โ mlb
2015๋ 3์ 12์ผ 21์ 37๋ถ์ Ben Alpert [email protected] ์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด split ํจ์๋ฅผ ์ ๊ท์๊ณผ ํจ๊ป ์ฌ์ฉํ ๋ค์ ์บก์ฒ๋ ๋ถ๋ถ์ ๋ฐ๊ฟ ์ ์์ต๋๋ค.
var parts = "๋๋ ์์ ๋๋ค. ์๋ ๋ฌด์ด๋ผ๊ณ ํฉ๋๋ค. MOOOOO.".split(/(\bmoo+\b)/gi);
for (var i = 1; i < parts.length; i += 2) {
๋ถํ[i] = ;}๋ฐํ{๋ถ์};
๋ถ๋ถ๋ช ํ ๊ฒฝ์ฐ ์๋ ค์ฃผ์ญ์์ค.โ
์ด ์ด๋ฉ์ผ์ ์ง์ ํ์ ํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์์ผ๋ก ๋ฌธ์์ด์ ์ผ๋ถ๋ฅผ ๊ฐ์กฐ ํ์ํ๋ ค๊ณ ํ ๋๋ ์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค(์: <span>
ํ๊ทธ๋ก ๊ต์ฒด). ์์ @spicyj ์๋ฃจ์
์ ๊ธฐ๋ฐ์ผ๋ก ๋ชจ๋์ ๋ง๋ค์์ต๋๋ค. ๊ด์ฌ ์๋ ์ฌ๋: iansinnott/react-string-replace
@iansinnott ๊ณต์ String.prototype.replace
API๊ฐ ํ์ํ๋ค๋ ๊ฒ์ ๊นจ๋ฌ์์ต๋๋ค(๊ต์ฒด ๊ธฐ๋ฅ ๋ด์์ ์ ๊ท ํํ์์ ๋ํ ๊ฐ๋ณ ์ผ์น ๊ทธ๋ฃน์ ๋ํ ์ก์ธ์ค ํ์). ๋ณ๊ฒฝ ์ฌํญ์ด ๋จ์ํ ํจ์น ์ด์(๊ทธ๋ฆฌ๊ณ API ๋ณ๊ฒฝ์ด ํ์ํจ)์ด ๋ ๊ฒ์ด๋ผ๋ ๊ฒ์ ๊นจ๋ฌ์์ผ๋ฏ๋ก ์ ์ ์ฅ์๋ฅผ ๋ง๋ค์์ต๋๋ค. https://github.com/oztune/string-replace-to-array
react-string-replace
์ด ์๊ตฌ ์ฌํญ์ ๋ง์ง ์๋ ๊ฒฝ์ฐ:
๋ค์์ ํ
์คํธ ๋ฌธ์์ด ๋ด์์ ํค์๋๋ฅผ ๊ฐ์กฐ ํ์ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ์ ์๊ฒ ํจ๊ณผ์ ์ด์์ต๋๋ค.
์ํํ HTML ์ค์ :
/**
* Find and highlight relevant keywords within a block of text
* <strong i="7">@param</strong> {string} label - The text to parse
* <strong i="8">@param</strong> {string} value - The search keyword to highlight
* <strong i="9">@return</strong> {object} A JSX object containing an array of alternating strings and JSX
*/
const formatLabel = (label, value) => {
if (!value) {
return label;
}
return (<span>
{ label.split(value)
.reduce((prev, current, i) => {
if (!i) {
return [current];
}
return prev.concat(<b key={value + current}>{ value }</b>, current);
}, [])
}
</span>);
};
formatLabel('Lorem ipsum dolor sit amet', 'dolor');
// <span>Lorem ipsum <b>dolor</b> sit amet</span>
์ฌ๋ฌ ๊ฐ์ ๋ํํ ์ ์๊ณ @richardwestenra ์๋ฃจ์ ์ ์ฝ๊ฐ์ ๋ณ๊ฒฝ์ ์ํํ ์ ์๋๋ก ์ผ๋ถ ํจํด๊ณผ ์ผ์นํ๋ ์ธ๊ธ์ ์ํด ์ด์ ๊ฐ์ ๊ฒ์ด ํ์ํ์ต๋๋ค. ๋๊ตฐ๊ฐ์๊ฒ ์ ์ฉํ ์๋ ์์ต๋๋ค.
/**
* Find and highlight mention given a matching pattern within a block of text
* <strong i="7">@param</strong> {string} text - The text to parse
* <strong i="8">@param</strong> {array} values - Values to highlight
* <strong i="9">@param</strong> {RegExp} regex - The search pattern to highlight
* <strong i="10">@return</strong> {object} A JSX object containing an array of alternating strings and JSX
*/
const formatMentionText = (text, values, regex) => {
if (!values.length)
return text;
return (<div>
{text.split(regex)
.reduce((prev, current, i) => {
if (!i)
return [current];
return prev.concat(
values.includes(current) ?
<mark key={i + current}>
{current}
</mark>
: current
);
}, [])}
</div>);
};
const text = 'Lorem ipsum dolor sit amet [[Jonh Doe]] and [[Jane Doe]]';
const values = ['Jonh Doe', 'Jane Doe'];
const reg = new RegExp(/\[\[(.*?)\]\]/); // Match text inside two square brackets
formatMentionText(text, values, reg);
// Lorem ipsum dolor sit amet <mark>Jonh Doe</mark> and <mark>Jane Doe</mark>
๋น์ทํ ๋ฌธ์ ๊ฐ ์์๊ณ ๋ฐ์ ํฌํธ๋ก ํด๊ฒฐํ์ต๋๋ค. ๋ ธ๋๋ฅผ ์ฝ๊ฒ ์ฐพ๊ธฐ ์ํด ๋ฌธ์์ด์ div๋ก ๋ฐ๊พธ๊ณ createPortal์ ์ฌ์ฉํ์ฌ ๋ฐ์ ๊ตฌ์ฑ ์์๋ฅผ ํด๋น div์ ๋ ๋๋งํ์ต๋๋ค.
@rmtngh ์ ๊ทธ๋ ๊ฒ ํด์ผ ํ๋์ง ๊ถ๊ธํฉ๋๋ค. ๊ณผ๋ถํ ์๋ ์์ ๊ฒ ๊ฐ์ต๋๋ค. ๋น ๋ฐ์ ์ฝ๋๋ฅผ ์ธํฐ๋ ์ด์คํ๊ณ ์์ต๋๊น?
์ด ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ์ฑ
๊ณผ ๊ด๋ จํ์ฌ string-replace-to-array
(์ ๋ ์ ์์
๋๋ค)๋ฅผ ๋ค์ ์ถ์ฒํ๊ณ ์ถ์ต๋๋ค. ์ฌ๋ฌ ํ๊ฒฝ์์ ์ ํฌ์ ์๊ฐ ํ
์คํธ๋ฅผ ๊ฑฐ์ณค์ต๋๋ค. ๋ํ ๋งค์ฐ ์์ต๋๋ค(์ ์ฒด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ https://github.com/oztune/string-replace-to-array/blob/master/string-replace-to-array.js ํ์ผ์
๋๋ค).
๋ค์์ ์ ๊ท์์ ์ฌ์ฉํ ์ฌ์ฉ ์์ ๋๋ค.
import replace from 'string-replace-to-array'
// The API is designed to match the native 'String.replace',
// except it can handle non-string replacements.
replace(
'Hello Hermione Granger...',
/(Hermione) (Granger)/g,
function (fullName, firstName, lastName, offset, string) {
return <Person firstName={ firstName } lastName={ lastName } key={ offset } />
}
)
// output: ['Hello ', <Person firstName="Hermione" lastName="Granger" key={ 0 } />, ...]
@oztune ๋ต์ฅ์ ๋ณด๋ด์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค. ์ด ๊ฒฝ์ฐ CMS์ wysiwyg ํธ์ง๊ธฐ์์ ๊ฐ์ ธ์จ html ๋งํฌ์
๋ฌธ์์ด์ด ์์ผ๋ฉฐ ํด๋น ๋งํฌ์
๋ด๋ถ์ ํน์ ์์น์ ๋ฐ์ ๊ตฌ์ฑ ์์๋ฅผ ๋ฐฐ์นํ๊ณ ์ถ์ต๋๋ค.
ํฌํธ์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ๋ซ๋ค๊ณ ์๊ฐํ์ญ๋๊น? ํฌํธ์ด ํ๋ ์ผ์ ์ผ๋ฐ ๊ตฌ์ฑ ์์๋ฅผ ๋ ๋๋งํ๋ ๊ฒ๋ณด๋ค ๋น์ธ์ง ์์ ๊ฐ์ฅ ๊ฐ๊น์ด ๋
ธ๋ ๋์ ๋ค๋ฅธ ๋
ธ๋ ๋ด๋ถ์ ๊ตฌ์ฑ ์์๋ฅผ ๋ ๋๋งํ๋ ๊ฒ์ด๋ฉฐ ์ ์ผํ ์ถ๊ฐ ๋จ๊ณ๋ ๊ธฐ๋ณธ js ๊ต์ฒด๋ก ์ํํ ์ ์๋ ๋ฌธ์์ด์ ๊ต์ฒดํ๋ ๊ฒ์
๋๋ค.
๋ด๊ฐ ๋ญ๊ฐ๋ฅผ ๋์น๊ณ ์์ต๋๊น? ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ค ์ด์ ์ด ์์ต๋๊น?
@rmtngh ๋น์ ์ดํ๋ ค๋ ์ผ์ ๋ฌ๋ ค ์๋ค๊ณ ๋งํ๊ณ ์ถ์ต๋๋ค. DOM ํธ๋ฆฌ์ ๋ค๋ฅธ ์์ญ์ ์ผ๋ถ React ๊ตฌ์ฑ ์์๋ฅผ ๋ฟ๋ฆฌ๋ ค๊ณ ํ๊ณ ํธ๋ฆฌ๊ฐ React๋ก ์์ง ๋ ๋๋ง๋์ง ์์ ๊ฒฝ์ฐ ํฌํธ์ด ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์ ๋๋ค. ๋ด๊ฐ ์ธ๊ธํ ๋ฐฉ๋ฒ์ ๊ต์ฒดํ๋ ค๋ ๋ถ๋ถ์ด ์ด๋ฏธ React ๊ตฌ์ฑ ์์ ๋ด๋ถ์์ ๋ ๋๋ง๋ ๊ฒฝ์ฐ์ ๊ฐ์ฅ ์ ์ฉํฉ๋๋ค.
ํ ์คํธ์ ํจํด์ด ์ฃผ์ด์ง ๋ ธ๋์ ๋ฐฐ์ด์ ๋ฐํํ๋ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
const highlightPattern = (text, pattern) => {
const splitText = text.split(pattern);
if (splitText.length <= 1) {
return text;
}
const matches = text.match(pattern);
return splitText.reduce((arr, element, index) => (matches[index] ? [
...arr,
element,
<mark>
{matches[index]}
</mark>,
] : [...arr, element]), []);
};
@wojtekmaj ๊ฐ์ฌํฉ๋๋ค
ํจํด์ ๊ทธ๋ฃน์ ๋ํ ๋ด ๋ฒ์ :
const replacePatternToComponent = (text, pattern, Component) => {
const splitText = text.split(pattern);
const matches = text.match(pattern);
if (splitText.length <= 1) {
return text;
}
return splitText.reduce((arr, element) => {
if (!element) return arr;
if(matches.includes(element)) {
return [...arr, Component];
}
return [...arr, element];
},
[]
);
};
const string = 'Foo [first] Bar [second]';
const pattern = /(\[first\])|(\[second\])/g;
replacePatternToComponent(string, pattern, <Component />);
typescript๋ฅผ ์ฌ์ฉํ์ฌ ์ ๊ทผ:
const formatString = (
str: string,
formatingFunction?: (value: number | string) => React.ReactNode,
...values: Array<number | string>
) => {
const templateSplit = new RegExp(/{(\d)}/g);
const isNumber = new RegExp(/^\d+$/);
const splitedText = str.split(templateSplit);
return splitedText.map(sentence => {
if (isNumber.test(sentence)) {
const value = values[Number(sentence)];
return Boolean(formatingFunction) ? formatingFunction(value) : value;
}
return sentence;
});
};
์ฌ์ฉ ์:
const str = '{0} test {1} test';
formatString(str, value => <b>{value}</b>, value1, value2);
๊ฒฐ๊ณผ:
<b>value1</b> test <b>value2</b> test
@rmtngh createportal์ ํตํด ๋งํฌ์ ๊ฐํ๋ฅผ ๋ฌ์ฑํ ๋ฐฉ๋ฒ์ ๋ํ ์ํ์ ์ ๊ณตํ ์ ์์ต๋๊น? ๋๋ ๋๊ฐ์ด ํ๋ ค๊ณ ํด์.
@Dashue ์์ด๋์ด๋ HTML ๋ฌธ์์ด๊ณผ ์ผ๋ง๋ ๋ง์ ์ ์ด ๊ถํ์ด ์๋์ง์ ๋ฐ๋ผ ๋งํฌ์
๋ด๋ถ์ ๋ฐ์ ๊ตฌ์ฑ ์์์ ๋ํ ์ผ๋ถ ๋์์ ๋ง๋๋ ๊ฒ์
๋๋ค.
์๋ฒ ์ธก์์ ๋ณ๊ฒฝํ ์ ์๋ค๋ฉด ์์์ ID๋ฅผ ๋ถ์ฌํ ์ ์์ต๋๋ค. ๋ค์๊ณผ ๊ฐ์ ๊ฒ:
<div id="component_target_1"></div>
๊ทธ๋ฆฌ๊ณ ๋ฐ์ ๋ด๋ถ์์ ์ ๊ท ํํ์์ผ๋ก \id="(component_target_\d)"\g
๋ฅผ ์ฐพ๊ณ ID(state.targets)๋ฅผ ์ ์ฅํ๊ณ ๊ตฌ์ฑ ์์๋ฅผ ๋ ๋๋งํฉ๋๋ค.
let mappedComponents
if(this.state.targets && this.state.targets.length){
mappedComponents = this.state.targets.map((id,index)=><MyComponent id={id} key={id} />)
}
๋ค์์ "MyComponent"์ ์ํ์ ๋๋ค.
import React from 'react'
import ReactDOM from 'react-dom'
export default class MyComponent extends React.Component {
constructor(props) {
super(props)
}
getWrapper(){
return document.getElementById(this.props.id)
}
render() {
if(!this.getWrapper()) return null
const content = <div>
Hello there! I'm rendered with react.
</div>
return ReactDOM.createPortal(
content,
this.getWrapper(),
);
}
}
HTML ๋ฌธ์์ด์ ๋ง์ด ์ ์ดํ ์ ์๋ ๊ฒฝ์ฐ์๋ ๋์ผํ ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ผ๋ถ ์์๋ฅผ ์ฐพ๊ณ ๋์ ์์๋ฅผ ๋ฌธ์์ด์ ์ฝ์ ํด์ผ ํ ์๋ ์์ต๋๋ค.
๋ฉ์ง ์ค๋ ๋ ๋ ์๋ค!
์ ๋ ์ด ์ค๋ ๋์ ์์ด๋์ด ์ค ์ผ๋ถ๋ฅผ ๊ตฌํํ๋ ๊ฐ๋จํ React Text Highlighter ํ์ ๋ง๋ค์์ต๋๋ค(๋ช ๊ฐ์ง ์ถ๊ฐ ๋ง๋ฒ๊ณผ ํจ๊ป...). ํฅํ ๋ฐฉ๋ฌธ์๊ฐ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์ ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
๋ค์์ map
์ฌ์ฉํ๋ ์๋ฃจ์
์
๋๋ค.
@sophiebits ์๋ฃจ์
์ ์ฌ๊ธฐ์์ ๋ถ๊ธฐ:
const reg = new RegExp(/(\bmoo+\b)/, 'gi');
const parts = text.split(reg);
return <div>{parts.map(part => (part.match(reg) ? <b>{part}</b> : part))}</div>;
์๋ฆ๋ค์ด ์๋ฃจ์ @rehat101
์ฌ๊ธฐ ๋ด ๊ฒฝ์ฐ์ ๊ฐ์ฅ ์ ์๋ํ๋ ๊ฒ์ด ์์ต๋๋ค. ๊ณต๋ฐฑ ๋ฌธ์๋ก ๋๋๊ณ ํน์ ๋จ์ด๋ฅผ ์ฐพ๋ ๊ฒ์ ๋๋ค.
HTML์์ ์กฐ๊ธ ์ง์ ๋ถํ์ง๋ง ๋๊ฐ ์๊ด ๐
๐ RegExp ์ ์ง๋ ๋ ์ด๊ฒ์ ์์ฃผ ๊นจ๋ํ๊ฒ ๋ง๋ญ๋๋ค. ๐๐๐
const Speech = ({ speech, speeches, setSpeeches, i, text }) => {
const highlightRegExp = new RegExp(
/you|can|do|it|puedes|hacerlo|pingรผinos|son|bellos/,
"gi"
);
const delineator = " ";
const parts = text.split(delineator);
return (
<div>
{parts.map(part =>
part.match(highlightRegExp) ? <b>{part + " "}</b> : part + " "
)}
</div>
);
};
์๋ฆ๋ค์ @rehat101
react-string-replace
์ด ์๊ตฌ ์ฌํญ์ ๋ง์ง ์๋ ๊ฒฝ์ฐ:
ํ๋ฅญํ! ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ค์ ๋ก ์๋ ๋ฌธ์์ด์ ์ก์ธ์คํด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
@nullhook ์ ์๋ฃจ์
์ ์ฝ๊ฐ ๋ฆฌํฉํ ๋งํ์ฌ ์ฟผ๋ฆฌ์ ๋ณ์๋ฅผ ํ์ฉํ๊ณ Google ๊ฒ์ ์๋ ์์ฑ์ ๋์์ ๋ชจ๋ฐฉํฉ๋๋ค.
js
const highlightQueryText = (text: string, filterValue: string) => {
const reg = new RegExp(`(${filterValue})`, 'gi');
const textParts = text.split(reg);
return (
<span style={{ fontWeight: 600 }}>
{textParts.map(part => (part.match(reg) ? <span style={{ fontWeight: 'normal' }}>{part}</span> : part))}
</span>
);
};
๊ทธ๋์ DOMPurify๋ฅผ ๊ตฌํํ์ฌ html-react-parser๋ก html ๋ฌธ์์ด์ ์ ๋ฆฌํ์ฌ ๋์ ๋งํฌ์ ์ ์ฐพ๊ณ JSX ๊ตฌ์ฑ ์์๋ก ๋ณํํ๋ ์ข์ ์กฐํฉ์ ์ฐพ์์ต๋๋ค. ์ ๋ฌ๋ props์ ํจ๊ป Rebass๋ฅผ ์๋ก ์ฌ์ฉํฉ๋๋ค. ๊ฝค ๋ฉ์ง๊ฒ ๋์์ต๋๋ค. ๋ ๊ฐ์ ํจํค์ง๋ ์์ ์ ํ์๋ฅผ ๋กค๋งํ๋ ์ค๋ฒํค๋๋ฅผ ํผํ๋ ๋ฐ ๋์์ด ๋ ๊ฒ์ ๋๋ค. ์ ๋ ์ด ํ์ ํจํค์ง๋ฅผ ์์ ์ฒ๋ฆฌํ์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ด๊ฒ์ผ๋ก ์ด๋ ค์์ ๊ฒช๊ณ ์๋ ์ฌ๋๋ค์ ์ํด https://codesandbox.io/s/eager-wiles-5hpff ์์ ์ด ์ฝ๋ํ์ ๊ฐ์น๋ฅผ ์ดํด๋ณด์ญ์์ค
ํค์ด ์ ์,
ํ
์คํธ๋ฅผ ๊ฐ์ ธ์์
๋ฐ์ ๊ตฌ์ฑ ์์! ํ์คํ ๋ถํ๊ต์ฒด์ฉ์ผ๋ก ์ข์๋ฏ
๊ตฌ์ฑ ์์๊ฐ ์๋ ๋ฌธ์์ด.
๊ณต์ ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
JAMstack ์ฌ์ดํธ์์ Markdown์ ๊ตฌ์ฑ ์์๋ก ์ ํํ๋ ๋ฐ ์ ์ฉํ ์๋ ์์ต๋๋ค.
์น์ ํ๋,
๋ฐ๋ฆญ
๋ฐ๋ฆญ R. ์ค์คํด, PT, DPT, MS, BCTMB, LMT, CSCS
LinkedIn์์ ์ ์ ํจ๊ปํ์ธ์: https://www.linkedin.com/in/derek-austin/
2020๋ 2์ 26์ผ ์์์ผ ์คํ 4:35 Jesse Lewis [email protected]์์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
๊ทธ๋์ DOMPurify๋ฅผ ๊ตฌํํ์ฌ HTML์ ์ญ์ ํ๋ ์ข์ ์กฐํฉ์ ์ฐพ์์ต๋๋ค.
html-react-parser๋ฅผ ์ฌ์ฉํ์ฌ ๋์ ๋งํฌ์ ์ ์ฐพ๊ณ ๋ณํํ๋ ๋ฌธ์์ด
JSX ๊ตฌ์ฑ ์์์ - ์ ๋ฌ๋ ์ํ๊ณผ ํจ๊ป Rebass๋ฅผ ์๋ก ์ฌ์ฉํฉ๋๋ค.
๊ฝค ๋ฉ์ง๊ฒ ๋์๊ณ ๋ ํจํค์ง๋ ์ค๋ฒ ํค๋๋ฅผ ํผํ๋ ๋ฐ ๋์์ด ๋ ๊ฒ์ ๋๋ค.
์์ ์ ํ์๋ฅผ ๋กค๋งํ๋ ค๋ฉด ์ด ํ์ ํจํค์ง๋ฅผ ๊ถ์ฅํ์ง ์์ต๋๋ค.
์ด๊ท ํ์ง ์๊ณ . ์ด๊ฒ์ผ๋ก ์ด๋ ค์์ ๊ฒช๊ณ ์๋ ์ฌ๋๋ค์ ์ํด ์์ง ๋ฒ์๋ฅผ ๋ฒ์ด ๋ฌ์ ์ ์์ต๋๋ค.
๊ฐ์น๊ฐ ์๋ ์ด codepen:
https://codesandbox.io/s/eager-wiles-5hpff. ๊ฐ์ ์ฌํญ์ ๋ํ ํผ๋๋ฐฑ
๋๋ฌด ๊ฐ์ฌํฉ๋๋ค.โ
๋น์ ์ด ๋๊ธ์ ๋ฌ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
https://github.com/facebook/react/issues/3386?email_source=notifications&email_token=AMV42QTV4FDXZIFXCGB3NZDRE3OATA5CNFSM4A5VRBI2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXH
๋๋ ๊ตฌ๋ ์ทจ์
https://github.com/notifications/unsubscribe-auth/AMV42QXARIOKOYSJ4C5IFQLRE3OATANCNFSM4A5VRBIQ
.
split
ํจ์๋ฅผ ์ ๊ท์๊ณผ ํจ๊ป ์ฌ์ฉํ๊ณ ๋ค์๊ณผ ๊ฐ์ด ์บก์ฒ๋ ๋ถ๋ถ์ ๋ฐ๊ฟ ์ ์์ต๋๋ค.var parts = "I am a cow; cows say moo. MOOOOO.".split(/(\bmoo+\b)/gi); for (var i = 1; i < parts.length; i += 2) { parts[i] = <span className="match" key={i}>{parts[i]}</span>; } return <div>{parts}</div>;
๋ถ๋ถ๋ช ํ ๊ฒฝ์ฐ ์๋ ค์ฃผ์ญ์์ค.
์ด๊ฒ์ ์ ์๋ํฉ๋๋ค. Angular์์ ์๋ํ๊ฒ ํ๋ ๋ฐฉ๋ฒ์ ์๋์? ๊ทํ์ ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ ์ด์ ๋ํ ์ง๋ฌธ์ ๊ฒ์ํ์ต๋๋ค.
https://stackoverflow.com/questions/60889171/wrap-certain-words-with-a-component-in-a-contenteditable-div-in-angular
์๋ ํ์ธ์ ์น๊ตฌ ์ฌ๋ฌ๋ถ, ๋์์ด ํ์ํฉ๋๋ค. ์ ๋ React Native๋ฅผ ์ฌ์ฉํ๊ณ ์์ผ๋ฉฐ DB์์ ์ถ์ถํ ํ ์คํธ์์ @mentions ๋ฅผ ๋ง๋ค๊ธฐ ์ํด ํ์(๊ธ๊ผด ์์, ๋งํฌ)์ ์ ์ฉํ๊ธฐ ์ํด ํ ์คํธ์์ ์ถ์ถํ ๊ฒ์ ๋๋ค. ํ ์คํธ๊ฐ 1๊ฐ์ ๋จ์ผ ์ผ์น ํญ๋ชฉ์ ์ฐพ์ผ๋ฉด ๊ต์ฒด๊ฐ ๋ชจ๋ ์ข์ง๋ง! ํ ์คํธ์ @๋ฉ์ ์ด ์ฌ๋ฌ ๊ฐ ์์ผ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
/////ํ
์คํธ ์: _ํค์ด @-id:1- ๋ชจ๋ ๊ฒ์ด ์ ์ ??
//// listusers ๋ฐฐ์ด, ์: [idusuario: "1", usuario: "@luigbren", ํ์: "@-id:1-".....]
const PatternToComponent = (text, usuarios,) => {
let mentionsRegex = new RegExp(/@-(id:[0-9]+)-/, 'gim');
let matches = text.match(mentionsRegex);
if (matches && matches.length) {
matches = matches.map(function (match, idx) {
let usrTofind = matches[idx]
//////////////////////////////////////////////////////////////////
const mentFormat = listusers.filter(function (item) {
const itemData = item.format;
return itemData.indexOf(usrTofind) > -1;
});
if (mentFormat.length > 0) {
let idusuario = mentFormat[0].idusuario
let replc = mentFormat[0].usuario
console.log(usrTofind) //// here find @-id:1-
console.log(replc) //// here is <strong i="12">@luigbren</strong> for replace
////////// now here replace part of the string, @-id:1- with a <Text> component
///////// with <strong i="13">@luigbren</strong> and the link, this is repeated for every <strong i="14">@mention</strong> found
parts = text.split(usrTofind);
for (var i = 1; i < parts.length; i += 2) {
parts[i] = <Text key={i} style={{ color: '#00F' }} onPress={() => { alert('but this is'); }}>{replc}</Text>;
}
return text = parts;
/////////////////////////////////////////////////////////////////////
} else {
return text
}
});
} else {
return text
}
return text
};
์ด๋ฐ ์์ผ๋ก ์ฝ๋๋ ํ ์คํธ์ ๋ฉ์ ์ด ํ๋๋ง ์๋ ๊ฒฝ์ฐ์๋ง ์ ์๋ํฉ๋๋ค. ์๋ฅผ ๋ค์ด '_hey what broken @-id:1- everything ok ??_' , ๊ทธ๋ฌ๋ ๋ ์ด์์ ๋ฉ์ ์ ๋ฐฐ์นํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค. , ์: '_์ด๋ด ๋ฌด์จ ์ผ์ด ์์์ด @-id:1- ๋ค ๊ด์ฐฎ์ ?? @-id:2- @-id:3-_' ... ์ค๋ฅ: TypeError: text.split์ ํจ์๊ฐ ์๋๋ฉฐ if ๋์ _parts = text.split(usrTofind);_ _parts = text.toString์ ๋ฐฐ์นํฉ๋๋ค. ().split(usrTofind);_ [Object Object] ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
html-react-parser
๋ฅผ ์ฌ์ฉํ์ฌ ๋ฌธ์์ด์ ๊ตฌ๋ฌธ ๋ถ์ํ ๋ค์ ๋
ธ๋ ์ด๋ฆ์ผ๋ก jsx ๊ตฌ์ฑ ์์๋ก ๋ฐ๊ฟ ์ ์์ต๋๋ค. ์ด ์ ํ์ ๋์ฒด๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฌธ์์ด์ ๋์ฒดํ์ฌ ๋ฐ์ ์์๋ฅผ ๋์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
parse(body, {
replace: domNode => {
if (domNode.name === 'select') { // or
return React.createElement(
Select, // your react component
{ },
domToReact(domNode.children)
);
}
}
๋๊ตฐ๊ฐ ๋ฌธ์์ด์์ react-router-dom
๋ฅผ ์ด๋ป๊ฒ ๋ฐ๊ฟ ์ ์๋์ง ์๋ ค์ฃผ์ธ์.
์์:
var text = "Are You okay <strong i="9">@sara</strong> ?";
var href= <Link to={{
pathname: '/user/sara',
}}> <strong i="10">@sara</strong> </Link>;
var replace = text.replace("@sara", href);
//output : Are You okey [Object Object] ?
[Object Object]๊ฐ ๋๊ตฐ์ง ์ ๋ง ๋ชจ๋ฅด๊ฒ ์ด์? ๋๋ "๊ด์ฐฎ์์ @sara"๋ผ๊ณ ๋งํ์ง๋ง ์ด ์ฝ๋๋ ๋ค๋ฅธ ์ฌ๋์ ๋ถ๋ ์ต๋๋ค!
react-native
์ ๊ฑฐ์ ๊ฐ์ ์ง๋ฌธ์ด ์์ต๋๋ค. ๋๊ตฌ๋ ์ง ์ ๋ฅผ ๋์์ฃผ์๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค.
์ด ํจํค์ง๋ฅผ ์ ์ธํ๊ณ ๋ ์๋ฌด๊ฒ๋ ์๋ํ์ง ์์์ต๋๋ค. https://www.npmjs.com/package/regexify-string
๋๋์ด ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค :
export const replaceWithHtml = (
text: string,
textToReplace: string,
replaceValue: any,
): any[] => {
const delimiter = '|||||'
return text && text.includes(textToReplace)
? text
.replace(textToReplace, `${delimiter}${textToReplace}${delimiter}`)
.split(delimiter)
.map((i) => {
if (i === textToReplace) {
return replaceValue
} else {
return i || null
}
})
: text
}
๊ทธ์ ๊ฐ์ด:
const text = 'This is an [icon]'
replaceWithHtml(
text,
'[icon]',
<i className="icon-cogs" />,
)
ํน์ ํค์๋๋ฅผ ํน์ ์์๋ก ๋์ฒดํ๋ ๊ฐ๋จํ ๋ณด๊ฐ ๋๊ตฌ๋ฅผ ์ํ์ต๋๋ค.
๋ด ์ถ๋ ฅ์ ์์ ์๋ฅผ ์ค์ด๊ธฐ ์ํด React.Fragment
์์ต๋๋ค.
const interpolate = (text, values) => {
const pattern = /([$0-9]+)/g
const matches = text.match(pattern)
const parts = text.split(pattern)
if (!matches) {
return text
}
return parts.map((part, index) => (
<Fragment key={part + index}>{matches.includes(part) ? values[part] : part}</Fragment>
))
}
// ...
<p>
{interpolate('$1 with $2 is fun!', {
$1: <em>Playing</em>,
$2: <strong>JavaScript</strong>,
})}
</p>
// <p><em>Playing</em> with <strong>JavaScript</strong> is fun!</p>
split()
์์ด๋์ด์ ๋ํด @sophiebits ์๊ฒ ๊ฐ์ฌ๋๋ฆฝ๋๋ค ๐
@pedrodurek ์ ์๋ฃจ์ ์ ๊ธฐ๋ฐ์ผ๋ก ๋ค์์ ๋ด ํน์ ์๊ตฌ ์ฌํญ์ ๋ํ ๊ฒ์ ๋๋ค(์ซ์ ๋์ ์ฝ์ ์ ์๋ ํค๋ก ๋ฒ์ญ).
export const insertComponentsIntoText = (
str: string,
replacements: {
[key: string]: React.ReactNode
}
) => {
const splitRegex = new RegExp(/\[\[(\w*)\]\]/g);
const parts = str.split(splitRegex);
return parts.map(part => {
if (replacements.hasOwnProperty(part)) {
return replacements[part];
}
return part;
});
};
์์:
insertComponentsIntoText(`"Please accept our [[privacyPolicyLink]] and [[termsLink].", {
"privacyPolicyLink": <a key="privacyPolicyLink" href="/privacy">Privacy Policy</a>,
"termsLink": <a key="termsLink" href="/terms">Terms and Conditions</a>
})
...๋๋ค...
Please accept our <a key="privacyPolicyLink" href="/privacy">Privacy Policy</a> and <a key="termsLink" href="/terms">Terms and Conditions</a>.
(์ค์ ๋ก ๋ฐฐ์ด์ด ๋๊ธฐ ๋๋ฌธ์ ํค๊ฐ ํ์ํ๊ณ ๋ฐ์์ ํค๊ฐ ์๋ ๋ฐฐ์ด ์์๋ฅผ ์ข์ํ์ง ์์ต๋๋ค.)
์ด ํจํค์ง๋ฅผ ์ ์ธํ๊ณ ๋ ์๋ฌด๊ฒ๋ ์๋ํ์ง ์์์ต๋๋ค. https://www.npmjs.com/package/regexify-string
์ ๋ ์. ์ด ํจํค์ง๋ง ์๋ํ๋๋ก ๋ชจ๋ ์๋ํ์ต๋๋ค. ๊ฐ์ฌํฉ๋๋ค!
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
split
ํจ์๋ฅผ ์ ๊ท์๊ณผ ํจ๊ป ์ฌ์ฉํ๊ณ ๋ค์๊ณผ ๊ฐ์ด ์บก์ฒ๋ ๋ถ๋ถ์ ๋ฐ๊ฟ ์ ์์ต๋๋ค.๋ถ๋ถ๋ช ํ ๊ฒฝ์ฐ ์๋ ค์ฃผ์ญ์์ค.