0
Warning: Each Child in a list should have a unique "Key" prop.

I believe I am not the only one who's confused by the Key System as get started at React. This question focuses on inclusive situations on adding a key prop.

Relevant reading I have done includes:

According to Adhithi Ravichandran, keys in iterations help React to identify which items have changed (added/removed/reordered).


1. For Component production, are keys supposed to be added in the iteration or component render method?

consider following movie component:

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. Is it appropriate to utilise a singleton id parser for generating key?

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;

Whereas Singleton.new() is called for parsing a new key, take following as an example:

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. Is this statement correct? "Key props are only useful for HTML Original tags such as div, span, button, but not for React.Component if this.props.key is unused."

Weilory
  • 2,621
  • 19
  • 35

1 Answers1

2

Conceptually, React does work in two phases:

  1. The render phase determines what changes need to be made to e.g. the DOM. During this phase, React calls render and then compares the result to the previous render.
  2. The commit phase is when React applies any changes. (In the case of React DOM, this is when React inserts, updates, and removes DOM nodes.) React also calls lifecycles like componentDidMount and componentDidUpdate during this phase. Phases

In render phase, for comparing between current result (a tree of React components/elements) to the previous render result (a tree of React components/elements), react uses reconciliation algorithm.

During this comparison, React uses key to match components/elements in the current result with components/elements in the previous render result.

If the key is same React just updates the component/element.

  1. For component

    Component instance stays the same so that state is maintained across renders. Component instance calls componentWillReceiveProps(), componentWillUpdate() and componentDidUpdate().

  2. For element

    React keeps the same underlying DOM node and only updates the changed attributes.

If the key is not same, React creates new component/element

  1. For component

    Component instance is initialized. Component instance calls componentWillMount() and then componentDidMount().

  2. For element new DOM nodes are inserted into the DOM.

If the component/element with key is present in previous result but not in current result then React removes them.

  1. For component

    Component instance calls componentWillUnmount(). Any state associated with the old instance is lost. Component instance is destroyed.

  2. For element old DOM nodes are destroyed.

Answering your questions

For Component production, are keys supposed to be added in the iteration or component render method?

Keys are supposed to be added in the iteration to identify the rendered child components/elements in a list uniquely.

 <Movie title={title} key={title} /> 

If you add key to div, the warning does not go. But the rule of reconciliation mentioned above will be applied to the div element.

Is it appropriate to utilise a singleton id parser for generating key?

If singleton id parser generates unstable keys like Math.random does then it's no use. Keys should be stable, predictable, and unique.

Is this statement correct? "Key props are only useful for HTML Original tags such as div, span, button, but not for React.Component if this.props.key is unused.

As you and in the docs, keys help React identify which items have changed, are added, or are removed. So items in my perspective refers to both component and element. So keys are applicable to both component and element. And I use it in both.

Sahil Raj Thapa
  • 2,353
  • 3
  • 12
  • 23
  • Bravo! appreciate it, A quick question please, is it appropriate to say: in diffing algorithm each time `render` is called, the `if two keys are matched` are checked at first, which help react to identify if it's needed to destroy the current node and build a new one. therefore, the best way to assigning keys are manually adding unique identifiers. Among created nodes if I target to change a specific one, I can increase the performance at large by passing same keys from previous except for the changed one? – Weilory Sep 09 '20 at 09:28
  • 1
    Yes, it will help in performance if we use same keys for every nodes except for the changed one. – Sahil Raj Thapa Sep 09 '20 at 10:57