在 for 循环中渲染 JSX

Rendering JSX inside for loop

我有以下数组:

0: {element: 'came', frequency: 3}
1: {element: 'here', frequency: 2}
2: {element: 'i', frequency: 1}

每个元素都是一个对象,显示文本中单词的频率。

我想做类似“最常见的单词是 X,使用了 Y 次。第二个最常见的单词是 Z,使用了 D 次。

所以我这样做了。 textObj 是包含对象的数组。

function Result() {
    const results = [];
    if (textObj.length != 0) {
      for (let i = 0; i < textObj.length; i += 2) {
        results.push(
          <div>
            <h1>Most frequent word was:</h1>
            <h2>
              '{textObj[i].element}' for {textObj[i].frequency} times
            </h2>
            <h1>Second most frequent word was:</h1>
            <h2>
              '{textObj[i++].element}' for {textObj[i++].frequency} times
            </h2>
          </div>
        );
      }

      return results;
    }

    return <div></div>;
  }

然后我渲染它在主要组件中返回。

在上面的例子中,我有一个短语“我来这里来这里”。出于某种原因,它在两者中都只显示“来了”这个词。但频率部分是正确的,它显示 3,然后显示 2。我尝试使用 textObj[i++]、textObj[i+1],但它说无法读取 'element'.

我做错了什么?

代码中的错误和错误修复

你有两个主要问题。其中之一是 i++,您已经解决了。 i++i 分配了一个新值(i + 1),因为它是后缀表示法(与前缀表示法 ++i 相反),该值仅在使用后分配,这解释了为什么单词 came 显示两次并且频率部分是正确的。但是,当您在 textObj[i++].frequency 中再次增加值时,您会再次更新 i,造成更多混乱。

结论:不要更新 i,只需使用 i + 1 即可。

现在另一个问题是,当您使用 i + 1 时,您将 运行 超出数组范围,而当 i = textObj.length - 1 时,这就是它说 cannot read 'element' 的原因。为避免这种情况,您必须将 for 循环中的条件更改为 let i = 0; i < textObj.length - 1; i += 2.

以更惯用的方式修复错误

话虽如此,您应该考虑一种更惯用的方法来执行此操作,类似于您将在许多 React 应用程序中看到的方法。 您可以通过使用 map() 来做到这一点,这将 return 所有值的数组 return 在回调中编辑。

const textObjData = [
  { element: "came", frequency: 3 },
  { element: "here", frequency: 2 },
  { element: "i", frequency: 1 },
];

function Result() {
  const [textObj, setTextObj] = React.useState(textObjData);

  return (
    <React.Fragment>
      {textObj.length !== 0 ? (
        // map takes three arguments here, the item in the array, the index and the array itself
        // we are using object destructuring to get the values of element and frequency so we don't have to deal with indices all the time
        textObj.map(({ element, frequency }, idx, elements) => {
          // check if we would run out of bounds for alst element, if yes => tell React to not render anyting by returning null
          if (idx === elements.length - 1) return null;
          // we are not out of bounds, so get next element and desctructur it as well
          // we need to assign new names to the destructured value to avoid naming conflicts with above destructured values
          const { element: nextElement, frequency: nextFrequency } = elements[idx + 1];
          return (
            <div>
              <h1>Most frequent word was:</h1>
              <h2>
                '{element}' for {frequency} times
              </h2>
              <h1>Second most frequent word was:</h1>
              <h2>
                '{nextElement}' for {nextFrequency} times
              </h2>
            </div>
          );
        })
      ) : (
        <div></div>
      )}
    </React.Fragment>
  );
}

ReactDOM.render(<Result/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

设计问题

现在查看代码片段,您会发现它仍然打印 "here" 两次,这是由于您的设计问题。你说你只想显示出现次数最多的两个词,但你仍然遍历整个数组,所以它首先显示索引为 0,1 然后是 1,2 然后是 2,3 然后是 3,4 等等的值。但是因为你只有 3 个值,所以只有索引为 1 ("here") 的值被打印两次。

可能的解决方案

如果只想显示出现次数最多的两个元素,则无需获取下一个元素。只需将 slice(0, 2)map() 结合使用即可最多呈现两个元素。

Please note: I have factored out the logic to show the word frequency to another component to get more concise and readable code.

const textObjData = [
  { element: "came", frequency: 3 },
  { element: "here", frequency: 2 },
  { element: "i", frequency: 1 },
];

function Result() {
  const [textObj, setTextObj] = React.useState(textObjData);

  return (
    <React.Fragment>
      {textObj.length !== 0 ? 
        // we are using object destructuring to get the values of element and frequency so we don't have to deal with indices all the time
        textObj.slice(0, 2).map(({ element, frequency }, idx) => (
          <WordFrequency
            key={element}
            element={element}
            frequency={frequency}
            rank={idx + 1}
          />
        ))
      : <div></div>}
    </React.Fragment>
  );
}

function WordFrequency({ element, frequency, rank }) {
  const mapping = {
    1: "M",
    2: "Second m",
  }

  return (
    <div>
      <h1>{mapping[rank]}ost frequent word was:</h1>
      <h2>
        '{element}' for {frequency} times
      </h2>
    </div>
  );
}

ReactDOM.render(<Result/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

如果您真的想显示出现次数最多的单词列表,您只需删除 slice() 即可。

const textObjData = [
  { element: "came", frequency: 3 },
  { element: "here", frequency: 2 },
  { element: "i", frequency: 1 },
];

function Result() {
  const [textObj, setTextObj] = React.useState(textObjData);

  return (
    <React.Fragment>
      {textObj.length !== 0 ? 
        // we are using object destructuring to get the values of element and frequency so we don't have to deal with indices all the time
        textObj.map(({ element, frequency }, idx) => (
          <WordFrequency
            key={element}
            element={element}
            frequency={frequency}
            rank={idx + 1}
          />
        ))
      : <div></div>}
    </React.Fragment>
  );
}

function WordFrequency({ element, frequency, rank }) {
  return (
    <div>
      <h1>#{rank} most frequent word was:</h1>
      <h2>
        '{element}' for {frequency} times
      </h2>
    </div>
  );
}

ReactDOM.render(<Result/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Please note: I am assuming, as your question suggests, that the elements in your array are already sorted in descending order.

最常用词和第二常用词 可以通过对数组进行排序并获取第一个和第二个元素来完成

var arr =  [{element: 'came', frequency: 3},
{element: 'here', frequency: 2},
{element: 'i', frequency: 1}]
var sortedArr = arr.sort((a, b) => b.frequency - a.frequency);

var mostFrequencWord = sortedArr[0];
var mostSecondFrequencWord = sortedArr[1];
console.log(`The most frequent word was ${mostFrequencWord.element}, for ${mostFrequencWord.frequency} time: `)
console.log(`The most frequent second word was ${mostSecondFrequencWord.element}, for ${mostSecondFrequencWord.frequency} time: `)