英文:
Can I use index of map function as key for my React components containing dynamic unpredictable text?
问题
以下是翻译好的部分:
我有这段代码,我正在将动态文本解析为单独的行,并为每行文本渲染单独的组件。
我使用map
函数创建一个元素数组,React要求列表中的每个元素都具有唯一的键。
我知道通常不建议使用index
作为键。但在这种情况下,我还能做什么呢?
问题
在这种情况下,我能否使用index
作为元素的key
,而不会出现问题?可能会出现什么问题?
注意1:我不能使用值作为键,因为所有行可能具有完全相同的值,因此它们将不是唯一的。
注意2:此代码在博客文章的管理表单中运行。我编写一些自定义标记文本,就像在StackOverflow问题文本区域中一样,我需要解析它以在屏幕上呈现为博客文章时为其添加适当的样式。例如:**粗体文本**
等。并且每行应该呈现为不同的段落。
更新:
我已经阅读了您在评论和答案中提到的文章。作者指出了以下内容:
我的情况是否满足这3个要求?
1 - 它们是否会更改?从理论上讲,它们会更改。
2 - 它们没有ID。
3 - 它们肯定没有被过滤。但它们是否被重新排序?如果您复制“line1\nline2\nline3”并粘贴到记事本中,然后将其更改为“line3\nline2\nline1”并将其粘贴回textarea
中,是否算作重新排序?我刚刚测试了一下,它呈现得很好。
无论如何,到目前为止,我还没有遇到任何问题,感觉可以安全使用。但我想要深入解释它在这种情况下是如何工作的。
function App() {
const [inputValue, setInputValue] = React.useState("line1\nline2\nline3");
const lineItems = inputValue.split("\n").map((line, index) =>
<TextLine
key={index}
index={index}
value={line}
/>
);
return(
<React.Fragment>
<textarea
onChange={(event) => setInputValue(event.target.value)}
value={inputValue}
style={{width: "300px", height: "60px"}}
/>
{lineItems}
</React.Fragment>
);
}
function TextLine(props) {
return(
<div>{props.value + " (key = " + props.index + ")"}</div>
);
}
ReactDOM.render(<App/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
<details>
<summary>英文:</summary>
I got this code where I'm parsing dynamic text into separate lines and rendering individual components for each line of text.
I'm using the `map` function to create an array for the elements and **React demands a unique key for each element on the list**.
I know usually it's not ideal to use `index` as the key. But in this case, what else can I do?
**QUESTION**
Can I use `index` as the `key` for the elements in this case without having issues? What could go wrong?
**Note1**: I cannot use the values as the keys, because all lines might have the exact same values, hence they wouldn't be unique.
**Note2**: This code runs inside an Admin form for BlogPosts. I write some custom markup text, just like in the textarea for questions on StackOverflow and I need to parse it to give it proper styles when rendered out on the screen as a blog post. Like: `**bold text**`, etc. And each line should be rendered as a different paragraph.
**UPDATE:**
I've read the article you all mentioned in comments and answer. And here's what the author points out:
---
[![enter image description here][1]][1]
Does my case meet all 3 requirements?
1 - Do they change? In theory they do.
2 - They have no ids.
3 - They are not filtered for sure. But are they reordered? What if you copy `"line1\nline2\nline3"` paste into Notepad and change it to `"line3\nline2\nline1"` and paste it back into the `textarea`. Does it count as re-ordering? I just tested it and it renders just fine.
Anyway, so far I haven't run into any issues and it feels safe to use. But I would like an in-depth explanation of how it works in this case.
---
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
function App() {
const [inputValue,setInputValue] = React.useState("line1\nline2\nline3");
const lineItems = inputValue.split("\n").map((line,index) =>
<TextLine
key={index}
index={index}
value={line}
/>
);
return(
<React.Fragment>
<textarea
onChange={()=>setInputValue(event.target.value)}
value={inputValue}
style={{width: "300px", height: "60px"}}
/>
{lineItems}
</React.Fragment>
);
}
function TextLine(props) {
return(
<div>{props.value + " (key = " + props.index + ")"}</div>
);
}
ReactDOM.render(<App/>, document.getElementById("root"));
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
<!-- end snippet -->
[1]: https://i.stack.imgur.com/J95le.png
</details>
# 答案1
**得分**: 4
以下是已翻译的部分:
**Note**: 如果项目具有唯一的 ID(且非原始列表),请不要使用索引,因为根据文档,这是一种反模式。
当项目没有唯一的 ID 时,您可以使用索引。
```javascript
const Numbers = ['One', 'Two', 'Three', 'Four'];
const App = () => (
<ul>
{Numbers.map(
(number, index) => <li key={index}>{number}</li>
)}
</ul>
)
没有唯一键时,React 无法区分元素是被移除还是仅内容发生了更改。
唯一键的解决方案...
1- 您可以创建一个生成唯一键/ID/数字/字符串的函数,并使用它。
2- 您可以使用 npm 包(库),如 uuid、uniqid、shortid...
3- 我建议使用从数据库获取的唯一 ID,如果您有的话。
英文:
Note: Don't use the index if the items have a unique id (and a non-primitives list should), because it's an anti-pattern as per documentation
When you don't have a unique id for the items, you can use the index.
const Numbers = ['One', 'Two', 'Three', 'Four'];
const App = () => (
<ul>
{Numbers.map (
(number, index) => <li key={index}>{number}</li>
)}
</ul>
)
Without a unique key, React couldn’t differentiate if the element was removed or just the content is changed.
Solutions for unique key...
1- You can create a function to generate unique keys/ids/numbers/strings and use that
2- You can use npm packages(library) like uuid, uniqid, shortid...
3- I recommend using the unique ID you get from the database, If you get it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论