使用 React 对脚注进行顺序编号

问题描述 投票:0回答:1

我正在尝试为我的博客的新 React 版本创建一个脚注组件,但是,到目前为止,我无法获得正确的编号。

我应用的逻辑与我对同一博客组件的 Web 组件版本所做的逻辑基本相同

  1. 根据可以有多少脚注计算当前脚注索引
    document.querySelectorAll(".footnote")
  2. 将该索引用于应出现脚注的
    <sup>
    标记。
  3. 将脚注索引和内容附加到帖子末尾的脚注容器中。

我认为由于 React 使用的渲染顺序,这不会起作用。有解决方法吗?也许有一个查询选择器方法可以只获取某个元素之前的元素?

这是我迄今为止所拥有的示例:

function Article() {
  return (
    <article>
      <p>The<FootNote html="Footnote 1" /> article content here<FootNote html="Footnote 2" />.</p>
      <FootNotesContainer />
    </article>
  )
}

function FootNotesContainer() {
  return (
    <div id="footnotes-container">
      <h2>Footnotes</h2>
    </div>
  )
}

function FootNote({ html }) {
  const [footNoteLink, setFootNoteLink] = React.useState("")
   
  React.useEffect(() => {
    const previousFootnotes =
      document.querySelectorAll(".footnote")
    const nextFootNoteNumber = previousFootnotes.length
         setFootNoteLink(nextFootNoteNumber.toString())

    const footNoteContent = document.createElement("div")
    footNoteContent.innerHTML = /* html */ `
      <a 
        href="#footnote-base-${nextFootNoteNumber}"
        id="footnote-${nextFootNoteNumber}"
        className="no-underline"
      >${nextFootNoteNumber}</a>:
      ${html}
    `

    const footNoteContainer = document.querySelector(
      "#footnotes-container"
    )
    footNoteContainer.appendChild(footNoteContent)
  }, [html])


  return (
    <sup className="footnote">
      <a
        href={`#footnote-${footNoteLink}`}
        id={`footnote-base-${footNoteLink}`}
        className="text-orange-400 no-underline"
      >
        {footNoteLink}
      </a>
    </sup>
  )
}

ReactDOM.createRoot(
  document.getElementById("root")
).render(
  <Article />
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

<div id="root"></div>

reactjs react-hooks web-component
1个回答
0
投票

实现此目的的一种方法是使用 es6 生成器函数。这是基本生成器函数的示例:

function* genId() {
    var index = 0;
    while (true)
        yield index++;
    }
}

let gen = idMaker();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2

了解有关生成器函数的更多信息这里

这是修改和更新的代码:

function Article() {
  return (
    <article>
      <p>The<FootNote html="Footnote 1" /> article content here<FootNote html="Footnote 2" />.</p>
      <FootNotesContainer />
    </article>
  );
}

function FootNotesContainer() {
  return (
    <div id='footnotes-container'>
      <h2>Footnotes</h2>
    </div>
  );
}

function* generateId() {
  let idCounter = 1;
  while (true) {
    yield idCounter++;
  }
}

const gen = generateId();

function useFootnoteId() {
  const [id, setId] = useState(0);

  React.useEffect(() => {
    setId(gen.next().value);
  }, [gen]);

  return id;
}

function FootNote({ html }) {
  const footNoteLink = useFootnoteId();

  useEffect(() => {
    const footNoteContent = document.createElement('div');
    footNoteContent.innerHTML = /* html */ `
    <a href="#footnote-base-${footNoteLink}" id="footnote-${footNoteLink}" className="no-underline">${count}</a>:
    ${html}
    `;
    const footNoteContainer = document.querySelector(
      '#footnotes-container'
    );
    footNoteContainer.appendChild(footNoteContent);

    return () => {
      // Cleanup function to remove the footnote content when the component unmounts
      footNoteContainer.removeChild(footNoteContent);
    };
  }, [html, footNoteLink]);

  return (
    <sup className='footnote'>
      <a
        href={`#footnote-${footNoteLink}`}
        id={`footnote-base-${footNoteLink}`}
        className='text-orange-400 no-underline'
      >
        {footNoteLink}
      </a>
    </sup>
  );
}

ReactDOM.createRoot(
  document.getElementById("root")
).render(
  <Article />
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

<div id="root"></div>

主要变化

  • 我们不再使用

    previousFootnotes.length
    来计算
    footNoteLink
    是什么。相反,我们使用
    useFootnoteId
    generateId
    函数。

    注意:我们已经删除了 DOM 读取,因此删除脚注等操作可能需要额外的步骤。

  • 我们在

    FootNotesContainer
    中实现了清理功能,以避免由于过度重新渲染而创建不必要的脚注。

现在脚注应该按照您希望的方式工作。

© www.soinside.com 2019 - 2024. All rights reserved.