【问题标题】:Wrap substrings in React components在 React 组件中包装子字符串
【发布时间】:2021-08-04 10:24:53
【问题描述】:

我有一个FragmentedString 类,它是一个带有一个或多个不同子字符串的字符串。

class FragmentedString {
    str: string;
    fragments: Array<{
        id: string;
        start: number;
        end: number;
    }>
}

之前已完成确保此分段字符串有效所需的所有验证。假设我们有以下FragmentedString,每个单词“substring”都是一个子字符串。

This is a beautiful string with a few substrings, such as this substring and this other substring.
This is a beautiful string with a few [substring]s, such as this [substring] and this other [substring].

如果我必须将每个子字符串包装在 &lt;a&gt; 标记中,我会插入它们并在 div 上设置 dangerouslySetInnerHtml。但是如果我想将这些包装在 React 组件中呢?我怎样才能做到这一点?我想到了eval,这不仅听起来是个坏主意,而且我不确定它是否支持 TypeScript 或 JSX。你怎么看?

编辑

为了避免 XY 问题:我希望根据单击的子字符串更改父组件的状态。在 React 中应该是这样的。

class Component {
    handleEvent(e) {
        // use e.target.name to extract the substring id, and set the parent state using a method passed as a prop
    }
    render() {
       return (
           <p>String <a name="substring_id" onClick={this.handleEvent.bind(this)}>substring</a></p>
       )
    }
}

请注意,尽管我在这里使用&lt;a&gt; 及其name 属性来存储id,但这可能不是正确的决定,我让你判断。

【问题讨论】:

  • 为什么不创建一个能够在没有任何dangerouslySetInnerHtml 的情况下呈现FragmentedString 的组件?
  • 嗯,是的,问题是如何。如何在字符串中插入 React 标签?
  • 你一开始就不会那样做。组件应该将字符串拆分为给定片段的几个部分,然后从将片段包装在所需标签中的部分创建正确的标记。
  • 这是我最近对类似问题的回答...stackoverflow.com/questions/68574191/…
  • @a2br 当然,看我的回答:)

标签: javascript node.js reactjs


【解决方案1】:

这是一个例子(可能有一个错误或其他奇怪的地方)。

实时示例here on CodeSandbox(由于 TypeScript 等,无法将其设置为可以在这里工作的 sn-p)。

import React from "react";

interface FragmentedString {
  str: string;
  fragments: Array<{
    id: string;
    start: number;
    end: number;
  }>;
}

function FragmentedStringRenderer({
  fragmentedString,
  renderFragment
}: {
  fragmentedString: FragmentedString;
  renderFragment: (id: string, content: string) => React.ReactChild;
}) {
  const { str, fragments } = fragmentedString;
  const out: React.ReactChild[] = [];
  // Assumes `fragments` is in order and doesn't overlap
  let currStart = 0;
  for (let i = 0; i < fragments.length; i++) {
    const { id, start, end } = fragments[i];
    if (currStart < start) {
      // need to add a plaintext fragment
      out.push(<>{str.substring(currStart, start)}</>);
    }
    out.push(renderFragment(id, str.substring(start, end)));
    currStart = end;
  }
  if (currStart < str.length) {
    // need to add a final fragment
    out.push(<>{str.substring(currStart)}</>);
  }
  return React.createElement(React.Fragment, {}, [...out]);
}

const fs: FragmentedString = {
  str: "Hello, world! Are you happy?",
  fragments: [
    { id: "noun", start: 7, end: 12 },
    { id: "adj", start: 22, end: 27 }
  ]
};


export default function App() {
  return (
    <div className="App">
      <FragmentedStringRenderer
        fragmentedString={fs}
        renderFragment={(id: string, text: string) => (
          <a href={`#${id}`}>{text}</a>
        )}
      />
    </div>
  );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-05
    • 2018-07-15
    • 2017-11-19
    • 2017-10-11
    • 2018-07-28
    • 1970-01-01
    • 1970-01-01
    • 2019-10-25
    相关资源
    最近更新 更多