在 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: `)
我有以下数组:
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: `)