如何使用组件

时间:2018-02-05 04:48:17

标签: javascript arrays angularjs reactjs replace

首先,我主要是一名AngularJS开发人员,最近切换到React,我决定将我之前开发的一个角度webapp转换为一个反应应用程序。我对组件ExpressiveText有一点问题,它在字符串中搜索匹配列表对象上的属性,并在其位置插入一个组件TriggerModal,当单击时触发一个模式更多详细资料。因此,传递到ExpressiveTest的属性为:texttagstagsProperty

text是一个字符串(即"My search string"

tags是一个对象数组(即[{id: 1, name: 'my', data: {...}}, {id: 2, name: 'string', data: {...}}]

tagsProperty是要搜索为“标记”的属性的名称(即name

我跟着this issue一起尝试制定一个如何处理这个问题的想法。我之所以提到我来自angular的原因是因为我之前创建的组件只使用text.replace(regex, match => <trigger-modal data={tags[i]} />)之类的东西,然后使用angulars $compile函数来渲染文本中的组件。使用react似乎不太可能。这就是我在ExpressiveText组件中尝试的内容:

class ExpressiveTextComponent extends React.Component {
  constructor (props) {
    super(props);
    this.filterText = this.filterText.bind(this);
  }
  filterText () {
    let text = this.props.text;
    this.props.tags.map(tag => {
      const regex = new RegExp(`(${tag[this.props.tagsProperty]})`, 'gi');
      let temp = text.split(regex);
      for(let i = 1; i < temp.length; i+=2){
        temp[i] = <TriggerModal data={tag} label={tag[this.props.tagsProperty]} />;
      }
      text = temp;
    });
    return text;
  }
  render () {
    return (
      <div className={this.props.className}>{this.filterText()}</div>
    );
  }
}

这适用于第一个标签。它的问题是,一旦它转到第二个标签上的maptext就是一个数组。我尝试添加一个条件来检查text是否是一个数组,但问题变成了text数组变得嵌套而且在下一次迭代时不起作用。我非常难以理解如何处理这个问题。我也尝试dangerouslySetInnerHTML使用text.replace(...),但这也不起作用,只是渲染[object Object]来代替组件。非常感谢任何帮助或建议,我不得不说这可能是我转换到React后遇到的唯一主要问题,否则它非常简单。

编辑:由于我有一个问题要求给定输入和更多说明的预期输出,我正在寻找的是给出此输入的组件:

<ExpressiveText text="my text" tags={{id: 1, name: 'text'}} tagsProperty="name" />

会渲染

<div>my <TriggerModal label="text" data={...} /></div>

具有功能TriggerModal组件。

2 个答案:

答案 0 :(得分:0)

如果我理解你想要完成的事情是正确的,那么这就是实现这一目标的一种方法。如果我误解了你的问题,我很抱歉。此外,这是伪代码,我会尝试用实际代码填充它。对不起,如果这很难理解,请告诉我,我会尽力澄清

filterText () {
    let text = [this.props.text];

    for (let item in this.props.tags) {
        //item will be something like {id: 1, name: 'text'}

        let searchString = new RegExp(item.name, 'gi');

        //loop through text array and see if any item matches search string regex.
        while (text.some(val => val.test(searchString)) {
            //if we are here, at least one item matches the regexp
            //loop thru text array, and split any string by searchString, and insert <TriggerModal> in their place
            for (let i = text.length-1; i >=0; i--) {
                //if text[i] is string and it matches regexp, then replace with nothing
                text[i].replace(searchString, "")
                //insert <trigger modal>       
                text.splice(i, 0, <TriggerModal ... />)
            } 
        //end of while loop - test again to see if search string still exists in test array
        }
    }
    return text;
  }

答案 1 :(得分:0)

看起来我找到了解决方案。

filterText () {

  let text = this.props.text.split(' '),
    replaceIndexes = [];

  if(this.props.tags.length > 0) {

    this.props.tags.map(tag => {

      const regex = new RegExp('(' + tag[this.props.tagsProperty] + ')', 'gi');

      for(let i = 0; i < text.length; i++){

        if(text[i].match(regex)){

          /** 
           * Pretty simple if its a one-word tag, search for the word and replace.
           * could potentially cause some mis-matched tags but the words 
           * in my usecase are pretty specific, unlikely to be used in 
           * normal dialogue.
           */
          text[i] = <TriggerModal data={tag} label={tag[this.props.tagsLabelProperty || 'name']} />;

        }else{

          // for tags with spaces, split them up.
          let tempTag = tag[this.props.tagsProperty].split(' ');

          // check for length
          if(tempTag.length > 1) {

            // we will be replacing at least 1 item in the array
            let replaceCount = 0,
              startIndex = null;

            // If the first word of tempTag matches the current index, loop through the rest of the tempTag and check to see if the next words in the text array match
            if(tempTag[0].toLowerCase() === text[i].toLowerCase()){

              startIndex = i;
              replaceCount += 1;

              // loop through temp array
              for (let j = 0; j < tempTag.length; j++) {

                if(tempTag[j].toLowerCase() === text[i+j].toLowerCase()){
                  replaceCount += 1;
                }

              }

              // Push data into replaceIndexes array to process later to prevent errors with adjusting the indexes of the text object while looping
              replaceIndexes.push({
                startIndex: startIndex,
                replaceCount: replaceCount,
                element: <TriggerModal data={tag} label={tag[this.props.tagsLabelProperty || 'name']} />
              });

            }

          }
        }
      }

    });

  }

  // Loop through each replace index object 
  replaceIndexes.forEach((rep, index) => {
    text.splice(rep.startIndex - index, rep.replaceCount, [rep.element, ', ']);
  });

  // Since we stripped out spaces, we need to put them back in the places that need them.
  return text.map(item => {
    if(typeof item === "string"){
      return item + ' ';
    }
    return item;
  });

}

编辑:这实际上是非常错误的。我最终放弃了我自己的解决方案,转而支持this package