React: Bagaimana cara mengganti bagian string dengan komponen?

Dibuat pada 12 Mar 2015  ·  40Komentar  ·  Sumber: facebook/react

Saya memiliki kode ini yang jelas tidak berfungsi:

    _.each(matches, (match) ->
      string = string.replace(match, ->
        <span className="match" key={i++}>{match}</span>
      )
    )

Karena itu akan menghasilkan string yang bercampur dengan objek. buruk aku tahu. Tetapi bagaimana saya bisa menambahkan komponen Bereaksi di dalam string? Yang saya inginkan adalah menyorot bagian dari string dengan komponen reaksi. Kasus yang sulit untuk dipecahkan, kurasa.

Komentar yang paling membantu

Anda dapat menggunakan fungsi split dengan regex dan kemudian mengganti bagian yang diambil, seperti:

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>;

Beri tahu saya jika itu tidak jelas.

Semua 40 komentar

sesuatu seperti ini harus bekerja:

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>")
        }} />
    )
  }
}

Ya, saya telah berpikir untuk menyalahgunakan dangerouslySetInnerHTML tetapi saya tidak menyukai ide ini. Metode ini dicap sebagai berbahaya untuk alasan yang baik.

Apakah tidak ada cara untuk mengajarkan Bereaksi untuk mengurai jsx dalam sebuah string? Memiliki React parse iE

var example = "this one word <span className="match" key={i++}>hello</span> is highlighted"

dan kembalikan ini dalam metode render?

@binarykitchen Anda dapat membuat elemen Bereaksi secara dinamis dan itulah yang perlu Anda lakukan di sini, Anda tidak dapat melakukannya hanya dengan penggantian string.

@syranide Ya, saya sudah tahu itu. Maksud saya adalah: bukankah ini akan menjadi fitur JSX/React yang bagus? Parsing string dan ubah tag apa pun di dalamnya menjadi komponen React anak.

Anda dapat menggunakan fungsi split dengan regex dan kemudian mengganti bagian yang diambil, seperti:

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>;

Beri tahu saya jika itu tidak jelas.

Parsing JSX pada saat runtime rawan kesalahan dan lambat, dan dapat dengan mudah memiliki implikasi keamanan – itu tidak akan lebih aman daripada yang berbahaya SetInnerHTML.

itu bisa menjadi sedikit masalah dengan tipe case

— mlb

Pada 12 mars 2015, pukul 21:37, Ben Alpert [email protected] menulis:

Anda dapat menggunakan fungsi split dengan regex dan kemudian mengganti bagian yang diambil, seperti:

var parts = "Saya seekor sapi; sapi berkata moo. MOOOOO.".split(/(\bmoo+\b)/gi);
for (var i = 1; i < bagian.panjang; i += 2) {
bagian[i] = ;}kembali

{bagian}
;
Beri tahu saya jika itu tidak jelas.


Balas email ini secara langsung atau lihat di GitHub.

Saya juga mengalami masalah ini ketika mencoba menyorot bagian dari string secara terprogram (yaitu ganti dengan tag <span> ). Saya akhirnya membuat modul berdasarkan solusi @spicyj di atas. Bagi siapa saja yang tertarik: iansinnott/react-string-replace

@iansinnott Terima kasih telah berbagi. Saya mulai menggunakannya kemudian menyadari bahwa saya akan membutuhkan String.prototype.replace API penuh (membutuhkan akses ke grup pencocokan individu untuk regexp dalam fungsi ganti). Saya menyadari perubahannya akan lebih dari sekadar tambalan sederhana (dan memerlukan perubahan API) jadi saya membuat repo baru: https://github.com/oztune/string-replace-to-array

Jika react-string-replace tidak sesuai dengan kebutuhan Anda:

https://github.com/EfogDev/react-process-string

Berikut ini berfungsi untuk saya sebagai cara untuk menyorot kata kunci dalam string teks, tanpa
pengaturan HTML yang berbahaya:

/**
 * 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>

Saya membutuhkan sesuatu seperti ini untuk menyebutkan yang cocok dengan beberapa pola sehingga dapat membungkus banyak nilai dan melakukan beberapa perubahan pada solusi @richardwestenra . Mungkin itu akan berguna bagi seseorang.

/**
 * 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>

Saya memiliki masalah serupa dan saya menyelesaikannya dengan portal reaksi, untuk menemukan simpul dengan mudah, saya mengganti string dengan div dan merender komponen reaksi saya menggunakan createPortal ke dalam div itu.

@rmtngh Saya ingin tahu mengapa Anda perlu melakukan itu. Sepertinya itu mungkin berlebihan. Apakah Anda menghubungkan kode non-bereaksi?

Mengenai solusi untuk masalah ini, saya ingin merekomendasikan kembali string-replace-to-array (Saya penulisnya). Ini telah melalui pertempuran dan teruji waktu di berbagai lingkungan. Ini juga cukup kecil (seluruh perpustakaan adalah file ini https://github.com/oztune/string-replace-to-array/blob/master/string-replace-to-array.js).

Berikut ini contoh penggunaan dengan regex:

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 Terima kasih atas balasan Anda, Dalam hal ini saya memiliki string markup html yang berasal dari editor wysiwyg dari CMS dan saya ingin menempatkan komponen reaksi di tempat tertentu di dalam markup itu.
Apakah menurut Anda lebih baik menggunakan perpustakaan daripada menggunakan portal? Saya pikir apa yang dilakukan portal adalah hanya merender komponen di dalam simpul lain alih-alih simpul terdekat yang tidak akan lebih mahal daripada merender komponen normal dan satu-satunya langkah tambahan adalah mengganti string yang dapat dilakukan dengan penggantian js asli.
Apakah saya kehilangan sesuatu? Apakah akan ada keuntungan menggunakan perpustakaan sebagai gantinya?

@rmtngh Saya akan mengatakan itu tergantung pada apa yang Anda coba lakukan. Jika Anda hanya mencoba untuk menaburkan beberapa komponen React di area berbeda dari pohon DOM Anda, dan pohon tersebut belum dirender dengan React, portal adalah cara yang harus dilakukan. Metode yang saya sebutkan paling berguna ketika bagian yang Anda coba ganti sudah dirender di dalam komponen React.

Berikut kode yang mengembalikan array node yang diberikan teks dan pola:

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]), []);
};

Terima kasih @wojtekmaj
Versi saya untuk grup dalam pola:

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 />);

Pendekatan menggunakan 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;
  });
};

Contoh penggunaan:

const str = '{0} test {1} test';
formatString(str, value => <b>{value}</b>, value1, value2);

Hasil:
<b>value1</b> test <b>value2</b> test

@rmtngh dapatkah Anda memberikan contoh bagaimana Anda mencapai pengayaan markup melalui createportal? Saya mencari untuk melakukan hal yang sama.

@Dashue Idenya adalah untuk membuat beberapa target untuk komponen reaksi Anda di dalam markup Anda, tergantung pada string HTML dan seberapa banyak kontrol yang Anda miliki terhadapnya,
Jika Anda dapat mengubahnya di sisi server, Anda mungkin ingin memberikan ID ke elemen Anda. Sesuatu seperti :
<div id="component_target_1"></div>
Dan di dalam reaksi, cari \id="(component_target_\d)"\g dengan regexp, simpan id (state.targets) dan render komponen Anda:

let mappedComponents
if(this.state.targets && this.state.targets.length){
            mappedComponents = this.state.targets.map((id,index)=><MyComponent id={id} key={id} />)
        }

Berikut adalah contoh "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(),
      );
  }
}

Jika Anda tidak memiliki banyak kendali atas string HTML, Anda masih dapat menggunakan pendekatan yang sama, Anda mungkin perlu menemukan beberapa elemen dan menyuntikkan elemen target ke dalam string.

Thread yang bagus guys!

Saya membuat pena React Text Highlighter sederhana yang mengimplementasikan beberapa ide di utas ini (dengan beberapa keajaiban ekstra...), semoga pengunjung di masa mendatang dapat merasakan manfaatnya.

Inilah solusi menggunakan map ,
solusi forking @sophiebits di sini:

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>;

Solusi cantik @rehat101

Inilah yang paling berhasil dalam kasus saya -- memisahkan dengan karakter spasi dan mencari kata-kata tertentu.

Ini sedikit berantakan di HTML tapi siapa yang peduli 😂

RegExp dan peta membuat ini sangat bersih. 💗💗💗

image

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>
  );
};

Cantik @rehat101

Jika react-string-replace tidak sesuai dengan kebutuhan Anda:

https://github.com/EfogDev/react-process-string

Cemerlang! Saya merasa ini sangat berguna karena sebagian besar waktu Anda benar-benar perlu mengakses string asli

Saya memfaktorkan ulang solusi
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> ); };

jadi saya menemukan kombinasi yang bagus dari penerapan DOMPurify untuk membersihkan string html dengan html-react-parser untuk menemukan markup yang ditargetkan di dalamnya dan mengubahnya menjadi komponen JSX - Saya menggunakan Rebass dengan props yang diteruskan sebagai contoh .. yang keluar dengan cukup baik, dua paket akan membantu Anda menghindari overhead penguraian parser Anda sendiri, saya hanya tidak akan merekomendasikan paket parser ini tanpa sanitasi. Bagi mereka yang berjuang dengan ini mungkin masih mencari codepen ini untuk apa nilainya: https://codesandbox.io/s/eager-wiles-5hpff. Umpan balik pada setiap perbaikan sangat dihargai juga.

Hei Jesse,
Itu sepertinya kombo yang sangat bagus untuk mengambil teks dan mengubahnya menjadi
komponen reaksi! Pasti akan bagus untuk mengganti bagian dari a
string dengan komponen.

Terima kasih telah berbagi.

Bisa juga berguna di situs JAMstack untuk mengubah penurunan harga menjadi komponen.

Salam,
Derek

Derek R. Austin, PT, DPT, MS, BCTMB, LMT, CSCS

Bergabunglah dengan saya di LinkedIn: https://www.linkedin.com/in/derek-austin/

Pada Rabu, 26 Februari 2020, 16:35 Jesse Lewis [email protected] menulis:

jadi saya menemukan kombinasi yang bagus untuk mengimplementasikan DOMPurify untuk membersihkan html
string dengan html-react-parser untuk menemukan markup yang ditargetkan di dalamnya dan mengonversinya
untuk komponen JSX - Saya menggunakan Rebass dengan props yang diteruskan sebagai contoh .. itu
keluar dengan cukup baik, kedua paket akan membantu Anda menghindari overhead
menggulirkan parser Anda sendiri, saya tidak akan merekomendasikan paket parser ini
tanpa sanitasi. Bagi mereka yang berjuang dengan ini mungkin masih bisa keluar
codepen ini untuk apa nilainya:
https://codesandbox.io/s/eager-wiles-5hpff. Umpan balik tentang peningkatan apa pun
sangat dihargai juga.


Anda menerima ini karena Anda berkomentar.
Balas email ini secara langsung, lihat di GitHub
https://github.com/facebook/react/issues/3386?email_source=notifications&email_token=AMV42QTV4FDXZIFXCGB3NZDRE3OATA5CNFSM4A5VRBI2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WZHJKTDN5
atau berhenti berlangganan
https://github.com/notifications/unsubscribe-auth/AMV42QXARIOKOYSJ4C5IFQLRE3OATANCNFSM4A5VRBIQ
.

Anda dapat menggunakan fungsi split dengan regex dan kemudian mengganti bagian yang diambil, seperti:

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>;

Beri tahu saya jika itu tidak jelas.

Ini bekerja dengan baik. Adakah cara untuk membuatnya berfungsi di Angular? Saya telah memposting pertanyaan tentang itu, menggunakan kode Anda:
https://stackoverflow.com/questions/60889171/wrap-certain-words-with-a-component-in-a-contenteditable-div-in-angular

Halo teman-teman, saya butuh bantuan Anda, saya menggunakan React Native dan yang perlu saya lakukan adalah dari teks yang saya ekstrak dari DB untuk menerapkan format (warna font, tautan) untuk membuat @sebutan , ketika mencari jika di teks menemukan 1 kecocokan tunggal membuat penggantian semuanya bagus, tapi! Jika ada beberapa @sebutan dalam teks, itu membuat saya error.

/////Contoh teks: _hey apa yang terjadi @-id:1- semuanya ok ??
//// listusers array-nya, contoh: [idusuario: "1", usuario: "@luigbren", format: "@-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
};

dengan cara ini kode berfungsi dengan baik untuk saya hanya ketika dalam teks hanya ada satu penyebutan, contoh '_hey apa yang terjadi @-id:1- semuanya ok ??_', tetapi ketika menempatkan lebih dari satu penyebutan itu memberi saya kesalahan , contoh: '_hey apa yang terjadi @-id:1- semuanya ok ?? @-id:2- @-id:3-_' ... Error: TypeError: text.split bukan fungsi dan jika alih-alih menempatkan _parts = text.split(usrTofind);_ saya menempatkan _parts = text.toString ().split(usrTofind);_ itu memberi saya kesalahan [Object Object]

Anda dapat menggunakan html-react-parser untuk mengurai string, lalu menggantinya dengan nama node dengan komponen jsx. Jenis penggantian ini akan memungkinkan Anda untuk menggunakan elemen reaksi secara dinamis dengan mengganti string.

      parse(body, {
        replace: domNode => {
          if (domNode.name === 'select') { // or
            return React.createElement(
              Select, // your react component
              { },
              domToReact(domNode.children)
            );
          }
        }

Seseorang memberi tahu saya bagaimana cara mengganti react-router-dom dalam string?

Contoh:

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] ?

saya benar-benar tidak tahu siapa itu [Objek Obyek]? saya mengatakan "Apakah Anda Oke @sara", tetapi kode ini memanggil orang lain!

Saya memiliki pertanyaan yang hampir sama di react-native , saya menghargai jika ada yang bisa membantu saya

pertanyaan saya

Tidak ada yang berhasil untuk saya kecuali paket ini https://www.npmjs.com/package/regexify-string

Saya menggunakan fungsi ini:

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
}

Seperti itu:

const text = 'This is an [icon]'
replaceWithHtml(
      text,
      '[icon]',
      <i className="icon-cogs" />,
)

Saya hanya ingin alat interpolasi sederhana, untuk mengganti kata kunci tertentu dengan elemen tertentu.

Untuk mengurangi jumlah elemen dalam output saya, saya menggunakan 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>

Terima kasih @sophiebits atas idenya di split() 🙏

Berdasarkan solusi @pedrodurek , berikut adalah sesuatu untuk kebutuhan spesifik saya (terjemahan dengan kunci yang dapat dibaca, bukan hanya angka):

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;
    });
};

Contoh:

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>
})

...menjadi...

Please accept our <a key="privacyPolicyLink" href="/privacy">Privacy Policy</a> and <a key="termsLink" href="/terms">Terms and Conditions</a>.

(Kunci diperlukan karena sebenarnya menjadi array, dan reaksi tidak menyukai elemen array tanpa kunci.)

Tidak ada yang berhasil untuk saya kecuali paket ini https://www.npmjs.com/package/regexify-string

Gerakan mengungkap kekerasan seksual demi menghapuskannya. Mencoba semuanya hanya paket ini yang berfungsi. Terima kasih!

Apakah halaman ini membantu?
0 / 5 - 0 peringkat