首页 > 解决方案 > 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 无效。”

标签: javascriptreactjskey

解决方案


从概念上讲,React 确实分两个阶段工作:

  1. 渲染阶段确定需要对 DOM 等进行哪些更改。在这个阶段,React 调用渲染,然后将结果与之前的渲染进行比较。
  2. 提交阶段是 React 应用任何更改的时候。(在 React DOM 的情况下,这是 React 插入、更新和删除 DOM 节点的时候。)在此阶段,React 还会调用诸如 componentDidMount 和 componentDidUpdate 之类的生命周期。 阶段

在渲染阶段,为了比较当前结果(React 组件/元素树)与之前的渲染结果(React 组件/元素树),react 使用协调算法。

在此比较期间,React 使用key将当前结果中的组件/元素与先前渲染结果中的组件/元素进行匹配。

如果key相同,React 只会更新组件/元素。

  1. 对于组件

    组件实例保持不变,以便在渲染之间保持状态。组件实例调用componentWillReceiveProps()、componentWillUpdate()和componentDidUpdate()。

  2. 对于元素

    React 保持相同的底层 DOM 节点,并且只更新更改的属性。

如果key不一样,React 会创建新的组件/元素

  1. 对于组件

    组件实例被初始化。组件实例调用componentWillMount(),然后调用componentDidMount()。

  2. 对于元素,新的 DOM 节点被插入到 DOM 中。

如果组件/元素key存在于先前的结果中但不存在于当前结果中,则 React 将其删除。

  1. 对于组件

    组件实例调用 componentWillUnmount()。与旧实例关联的任何状态都将丢失。组件实例被销毁。

  2. 对于元素,旧的 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 指的是组件和元素。所以键适用于组件和元素。我在两者中都使用它。


推荐阅读