8

I have a problem with the key props in a React JS component.

I'm getting

Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of Login. It was passed a child from App.

warning in console log. App component is as follows :

import React from 'react';
import Header from '../common/header';
import HeaderCompact from '../common/headerCompact';
import Footer from '../common/footer';


class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      lang: 1
    };
  }

  changeLang(name, event) {
    event.preventDefault();
    switch (name) {
      case "fra" :
        this.setState({lang: 2});
        break;
      case "ger" :
        this.setState({lang: 3});
        break;
      case "ned" :
        this.setState({lang: 4});
        break;
      default:
        this.setState({lang: 1});
    }
  }


  render() {
    let currentRoute = this.props.location.pathname.slice(1);
    let header = currentRoute === "" ? <Header onClick={this.changeLang} lang={this.state.lang}/> :
      <HeaderCompact currentRoute={currentRoute} onClick={this.changeLang} lang={this.state.lang}/>;
    return (
      <div>
        {header}
        {React.cloneElement(this.props.children, {lang: this.state.lang})}
        <Footer lang={this.state.lang}/>
      </div>

    );
  }
}

export default App;

And my login component is as follows :

import React from 'react';
import LoginForm from './loginForm';

const Login = ({currentLanguage}) => {

    const language = currentLanguage;

    return (
        <div className="container">
            <div className="row">
                <p className="col-lg-4 col-xs-12 col-md-4 loginTitle noPadding">{language.loginTitle}</p>
                <div className="col-lg-8 col-xs-12 col-md-8 loginForm noPadding">
                    <LoginForm currentLanguage={language}/>
                </div>
            </div>
        </div>
    );
};

export default Login;

I'm still new in React and I'm not sure what should I pass like a key and where?

UPDATE

LoginForm component :

import React from 'react';
import {Link} from 'react-router';

import TextInput from '../../common/formElements/textInput';
import LoginButton from '../../common/formElements/button';

class LoginForm extends React.Component {

    constructor(props, context) {
        super(props, context);

        this.state = {
            loginData: {
                username: '',
                password: ''
            },
            errors: {}
        };

        this.buttonClickHandle = this.buttonClickHandle.bind(this);
        this.loginHandle = this.loginHandle.bind(this);
    }

    loginHandle(event) {
        let field = event.target.name;
        let value = event.target.value;
        this.state.loginData[field] = value;
        return this.setState({loginData: this.state.loginData});
    }

    buttonClickHandle(event) {
        event.preventDefault();
        alert("It's clicked/n");
    }

    render() {
        const language = this.props.currentLanguage;

        return (
            <div className="contact_form">
                <form role="form" action="" method="post" id="contact_form">
                    <div className="col-lg-4 col-md-4 col-sm-4 col-xs-12 smScrPdLeft" style={{marginTop: 5}}>
                        <TextInput
                            type="text"
                            name="username"
                            label=""
                            placeholder={language.loginUsername}
                            className="templateInput loginUsername col-lg-12 col-md-12 col-sm-12 col-xs-12"
                            id="name"
                            sizeClass=""
                            onChange={this.loginHandle}
                            value={this.state.username}
                            errors={this.state.errors.username}
                        />
                    </div>
                    <div className="col-lg-4 col-md-4 col-sm-4 col-xs-12 smPadding" style={{marginTop: 5}}>
                        <TextInput
                            type="password"
                            name="password"
                            label=""
                            placeholder={language.loginPassword}
                            className="templateInput loginPassword col-lg-12 col-md-12 col-sm-12 col-xs-12"
                            id="password"
                            sizeClass=""
                            onChange={this.loginHandle}
                            value={this.state.password}
                            errors={this.state.errors.password}
                        />
                        <Link to="/" className="forgotPassLabel">{language.forgotPassword}</Link>
                    </div>
                    <div className="col-lg-4 col-md-4 col-sm-4 col-xs-12 btnLogin noPadding smScrPdRight" style={{marginTop: 4}}>
                        <LoginButton onClick={() => this.buttonClickHandle(event)} name="registration" value={language.loginBtnText} className="rightFloat" icon="user"/>
                    </div>
                </form>
            </div>
        );
    }
}

export default LoginForm;

Routes file :

import React from 'react';
import { IndexRoute, Route } from 'react-router';

import App from './components/App';
import HomePage from './components/HomePage';

const routes = (
    <Route path="/" component={App}>
        <IndexRoute component={HomePage}/>
    </Route>
);

export default routes;

HomePage Component

return (
    <div>
        <div className="sidebar-menu-container" id="sidebar-menu-container">

            <div className="sidebar-menu-push">

                <div className="sidebar-menu-overlay"></div>

                <div className="sidebar-menu-inner">

                    <section className="marginOnXs" style={{width: '100%', padding: 0}}>
                        <div className="container">
                            <div className="row hideOnXS">
                                <MainSlider />
                            </div>
                        </div>

                    </section>

                    <div id="cta-1" className="onlyOnDesktop">
                        <Login currentLanguage={languageHome}/>
                    </div>

                    <section className="why-us" style={{paddingTop: 0}}>
                        <Info currentLanguage={languageHome}/>
                    </section>
                    <div className="clearfix"></div>

                    <section className="featured-listing">
                        <CarsList allCars={carsList()} currentLanguage={languageHome}/>
                    </section>

                    <section className="contactSection">
                        <ContactForm currentLanguage={languageHome}/>
                    </section>
                </div>
            </div>
        </div>
    </div>
);
Jared Smith
  • 19,721
  • 5
  • 45
  • 83
Boky
  • 11,554
  • 28
  • 93
  • 163
  • Probably a silly question but: Did you remember to import your components? I got the very same message when I had inside a component, where MyComponent wasn't imported.. – Anders Martini Sep 10 '17 at 18:57
  • This can help you https://stackoverflow.com/questions/28329382/understanding-unique-keys-for-array-children-in-react-js/50551566#50551566 – Mahdi Bashirpour May 27 '18 at 11:18
  • I've edited your question. In the future with react questions please also include the `javascript` tag: for some reason SO's syntax highlighting won't work if you don't. Someone asked a question on meta about it 3 years ago, but apparently it died for want of attention. – Jared Smith Oct 12 '18 at 10:36

2 Answers2

17

I don't know how your LoginForm component looks like.

But each time you iterate over an array you have to set the key prop to each of the resulting DOM element as React needs it to optimize the re-rendering. For example:

<div className="container">
        {myarray.map((element, index) => {
            return <div key={'mykey' + index}>{element}</div>;
        })}
</div>

React for example will detect duplicates and only renders the first node with this key.

Richard Rutsche
  • 1,156
  • 8
  • 11
  • 1
    I updated my question. But I'm not iterating an array anywhere, I do not have map anywhere. – Boky Jun 06 '16 at 07:37
  • hm. What exactly is passed with `this.props.children` in your `App` component? Maybe this is an array? Everything else looks good to me. – Richard Rutsche Jun 06 '16 at 07:53
  • I updated the code for the App component. The state is passed; that is only a number. – Boky Jun 06 '16 at 07:56
  • No I mean the children that are passed to your `App` component. >> `{//the children you are passing here}`. This is the place where an array could be passed. See description at the top at https://facebook.github.io/react/tips/children-props-type.html – Richard Rutsche Jun 06 '16 at 08:08
  • The App component is called from routes file, from React Router. I updated my question with that file. – Boky Jun 06 '16 at 08:12
  • Oh man. I have no idea. Everything you posted looks good to me. The only component I did not see yet is `HomePage`. Guess for further inspection a running fiddle is needed. - Sorry – Richard Rutsche Jun 06 '16 at 08:37
  • It's really strange. I updated my question with HomePage component. And thanks ;-) – Boky Jun 06 '16 at 08:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/113894/discussion-between-richard-rutsche-and-boky). – Richard Rutsche Jun 06 '16 at 09:19
2

The reason behind this warning is that you have not passed 'key' property. React uses this property for optimizing the rendering process as in when something changes in React, a re-render will occur only for what all has changed.

If our children are dynamic and in case they get shuffled with random functions or new components are introduced in the beginning of an array, the re-render is likely to get messed up. So, assigning this 'key' property helps us make sure that the state and identity of our components is maintained through multiple renders. Please find below a sample code snippet demonstrating how to pass a key.

<MyComponent key={{item.key}}/>

The importance of key is beautifully explained here.

  • 2
    While certainly correct this answer would be improved by the addition of a code example. – Jared Smith Jul 20 '18 at 14:24
  • Thanks, @JaredSmith! Edited my answer. – Abhishek Maheshwari Oct 12 '18 at 08:11
  • I certainly appreciate you updating your answer, but please actually post the code *in* your answer: links can and do go dead. If the code example is one that you got from somewhere else as opposed to created yourself, by all means add the link for attribution but still post the code inside your actual answer. – Jared Smith Oct 12 '18 at 10:27
  • Thank you @JaredSmith for your feedback. Please correct me if you think I am still missing on anything. – Abhishek Maheshwari Dec 05 '18 at 08:24