javascript - React TypeScript:关键系统
问题描述
Warning: Each Child in a list should have a unique "Key" prop.
我相信我不是唯一一个在 React 入门时对Key System感到困惑的人。这个问题的重点是添加key
道具的包容性情况。
我做过的相关阅读包括:
根据Adhithi Ravichandran的说法,迭代中的键有助于 React 识别哪些项目已更改(添加/删除/重新排序)。
1. 组件制作,应该在迭代或组件渲染方法中添加key吗?
考虑以下电影组件:
class Movie extends React.Component<any, any> {
render():JSX.Element{
let styles:React.CSSProperties = {
width: "300px",
height: "120px",
display: "flex",
justifyContent: "space-around",
alignItems: "center",
borderRadius: "20px",
filter: "drop-shadow(0px 1px 3px #6d6d6d)",
WebkitFilter: "drop-shadow(3px 3px 3px #6d6d6d)",
backgroundColor: '#'+Math.floor(Math.random()*16777215).toString(16),
fontSize: '2.5rem',
margin: '20px',
color: '#fff',
}
return (
<>
{/* add key to this div tag? */}
<div style={styles}>
{this.props.title}
</div>
</>
)
}
}
function test():JSX.Element{
return (
<>
{
['The Avengers', 'Ip Man', 'Now You See Me'].map(
// or add key to this Movie tag?
title=>(<Movie title={title} />)
)
}
</>
);
}
2. 使用单例 id 解析器生成密钥是否合适?
class Singleton {
private static _instance:Singleton = new Singleton();
public _ind:number = 0;
public _ids:Array<string> = ['r0'];
public _memory:boolean = false;
public _remember:Array<string|boolean|number> = [];
constructor(){
if(Singleton._instance){
return Singleton._instance;
}
Singleton._instance = this;
}
public new():string{
this._ind += 1;
this._ids.push(`r${this._ind}`);
let tar = this._ids[this._ids.length-2];
if(this._memory){this._remember.push(tar)}
return tar;
}
public placeholder(cos:string|boolean|number):void{
if(this._memory){this._remember.push(cos)}
}
public last():string{
return this._ids[this._ids.length-2];
}
public start_memorize():void{
this._memory = true;
}
public end_memorize():void{
this._memory = false;
}
public dump_memory():Array<string|boolean|number>{
let tar = this._remember.concat();
this._remember = [];
return tar;
}
public redeem(num:number){
for(let i=0; i<num; i++){
this._ids.pop();
this._ind -= 1;
}
}
}
export default Singleton;
而Singleton.new()
在解析新密钥时调用,以以下为例:
class Card extends React.Component<any, any>{
props:React.ComponentProps<any>;
singleton:Singleton;
constructor(props:any) {
super(props);
this.singleton = new Singleton();
}
render(){
return (
<>
<div key={this.singleton.new()}>
</div>
</>
)
}
}
3. 这个说法正确吗?“Key props 仅对 div、span、button 等 HTML 原始标签有用,但如果 this.props.key 未使用,则对 React.Component 无效。”
解决方案
从概念上讲,React 确实分两个阶段工作:
- 渲染阶段确定需要对 DOM 等进行哪些更改。在这个阶段,React 调用渲染,然后将结果与之前的渲染进行比较。
- 提交阶段是 React 应用任何更改的时候。(在 React DOM 的情况下,这是 React 插入、更新和删除 DOM 节点的时候。)在此阶段,React 还会调用诸如 componentDidMount 和 componentDidUpdate 之类的生命周期。 阶段
在渲染阶段,为了比较当前结果(React 组件/元素树)与之前的渲染结果(React 组件/元素树),react 使用协调算法。
在此比较期间,React 使用key
将当前结果中的组件/元素与先前渲染结果中的组件/元素进行匹配。
如果key
相同,React 只会更新组件/元素。
对于组件
组件实例保持不变,以便在渲染之间保持状态。组件实例调用componentWillReceiveProps()、componentWillUpdate()和componentDidUpdate()。
对于元素
React 保持相同的底层 DOM 节点,并且只更新更改的属性。
如果key
不一样,React 会创建新的组件/元素
对于组件
组件实例被初始化。组件实例调用componentWillMount(),然后调用componentDidMount()。
对于元素,新的 DOM 节点被插入到 DOM 中。
如果组件/元素key
存在于先前的结果中但不存在于当前结果中,则 React 将其删除。
对于组件
组件实例调用 componentWillUnmount()。与旧实例关联的任何状态都将丢失。组件实例被销毁。
对于元素,旧的 DOM 节点被销毁。
回答您的问题
对于组件生产,是否应该在迭代或组件渲染方法中添加键?
应该在迭代中添加键以唯一地标识列表中呈现的子组件/元素。
<Movie title={title} key={title} />
如果将键添加到 div,则不会发出警告。但是上面提到的协调规则将应用于 div 元素。
使用单例 id 解析器生成密钥是否合适?
如果单例 id 解析器生成不稳定Math.random
的键,那么它就没有用了。密钥应该是稳定的、可预测的和唯一的。
这个说法正确吗?“Key props 仅对 HTML 原始标签有用,例如 div、span、button,但如果 this.props.key 未使用,则对 React.Component 无效。
正如您和在文档中一样,键帮助 React 识别哪些项目已更改、添加或删除。所以在我看来,items 指的是组件和元素。所以键适用于组件和元素。我在两者中都使用它。
推荐阅读
- aws-cdk - 如何检索 AWS ServiceCatalog 产品组合 ID 和产品 ID
- c - 发现为什么这些循环被标记为“无效的语句”的问题(警告:无效的语句 [-Wunused-value])
- javascript - Axios CORS 仅适用于无效请求
- django - 列表到字典并以所需格式打印
- javascript - NodeJS 中将产生的线程数
- python - vb.net 代码在 python 中转换。.net for 循环到 python for 循环
- html - 删除嵌套表之间的空间
- javascript - 录音未上传到服务器文件夹
- go - path.IsAbs 为 Windows 路径返回不正确的结果
- xamarin.forms - 视频播放时相机源丢失