当前位置: 首页 > 知识库问答 >
问题:

当映射的输入组件已经具有唯一键时,为什么会收到“唯一键道具”警告?

葛泳
2023-03-14

我试图在我的反应应用程序中创建一个表单。我创建了一个input.js组件,它被导入到我的contact.js组件中,然后映射。我得到一个“警告:数组或迭代器中的每个孩子都应该有一个唯一的“键”道具。检查控制台内部的输入的渲染方法,但是我不明白为什么,因为每个输入组件都已经设置了唯一的键。当我在铬检测仪的反应选项卡中检查它们时,它们都有一个唯一的密钥集。

这是我的contact.js组件:

import React, { Component } from 'react';
import Input from './Input/input';
import Button from './Button/Button';
import Spinner from '../UI/Spinner/Spinner';
import {checkValidity} from '../../shared/utility';

import axios from '../../axios-contact';

class ContactForm extends Component {
    state = {
        contactForm: {
            name: {
                elementType: 'input',
                elementConfig: {
                    inputprops: {
                        type: 'text',
                        id: 'name',
                        name: 'name',                                       
                        required: 'required'  
                    } ,
                    label: 'Name',                
                    htmlFor: 'name',
                    invalid: 'Please enter your firstname',
                    value: '',              
                },                
                validation: {
                    required: true,
                    minLength: 2,
                    maxLength: 30
                },
                valid: false,
                touched: false
            },
            company: {
                elementType: 'input',
                elementConfig: {
                    inputprops: {
                        type: 'text',
                        id: 'company',
                        name: 'company',                 
                        required: 'required'                    
                    },                
                    label: 'Company',
                    htmlFor: 'company', 
                    invalid: 'Please enter your company name',
                    value: '',
                },
                validation: {
                    required: true,
                    minLength: 2,
                    maxLength: 30
                },
                valid: false,
                touched: false
            },
            location: {
                elementType: 'input',
                elementConfig: {
                    inputprops: {
                        type: 'text',
                        id: 'location',
                        name: 'location',                 
                        required: 'required'
                    },
                    label: 'Company location (city / country)',
                    htmlFor: 'location',
                    invalid: 'Please enter your location',
                    value: '',
                },
                validation: {
                    required: true,
                    minLength: 2,
                    maxLength: 30
                },
                valid: false,
                touched: false
            },
            email: {
                elementType: 'email',
                elementConfig: {
                    inputprops: {
                        type: 'email',
                        id: 'email',
                        name: 'email',                 
                        required: 'required'                    
                    },
                    label: 'Email',
                    htmlFor: 'email',
                    invalid: 'Please enter a propper email address',
                    value: '',
                },
                validation: {
                    required: true,
                    isEmail: true,
                    minLength: 7,
                    maxLength: 40
                },
                valid: false,
                touched: false
            },
            phone: {
                elementType: 'input',
                elementConfig: {
                    inputprops: {
                        type: 'tel',
                        id: 'phone',
                        name: 'phone',                 
                        required: false                    
                    },
                    label: 'Phone',
                    htmlFor: 'phone',
                    invalid: 'Please enter a propper phone number',
                    value: '',
                },
                validation: {
                    required: false,
                    minLength: 6,
                    maxLength: 30
                },
                valid: true,
                touched: false
            },
            message: {
                elementType: 'textarea',
                elementConfig: {
                    inputprops: {
                        type: 'textarea',
                        id: 'message',
                        name: 'message',                  
                        required: 'required', 
                        rows: 4                   
                    },
                    label: 'Message',
                    htmlFor: 'message',
                    invalid: 'Please enter a message',
                    value: '',
                },
                validation: {
                    required: true,
                    minLength: 2,
                    maxLength: 500
                },
                valid: false,
                touched: false
            },
            compliance: {
                elementType: 'checkbox',
                containerClass: 'custom-control custom-checkbox',
                inputClass: 'custom-control-input',
                elementConfig: {
                    inputprops: {
                        type: 'checkbox',
                        id: 'gdpr',
                        name: 'gdpr',                    
                        required: 'required'                    
                    },
                    label: 'I consent to having this website store my submitted information so they can respond to my inquiry.',
                    htmlFor: 'gdpr',  
                    invalid: 'Please give your consent before proceeding',                 
                    value: '',
                },
                validation: {
                    required: true,
                    isCheckbox: true,
                    isToggled: false
                },
                valid: false,
                touched: false           
            }
        },
        formIsValid: false,
        loading: false,
        sent: false
    }

    contactHandler = ( event ) => {
        event.preventDefault();
        this.setState( { loading: true } );
        const formData = {}
        for (let formElementIdentifier in this.state.contactForm) {
            formData[formElementIdentifier] = this.state.contactForm[formElementIdentifier].elementConfig.value;
        }

        axios.post('/contacts.json', formData)
            .then(response => {
                this.setState({ loading: false, sent: true });
                console.log(formData);
            })
            .catch(error => {
                this.setState({ loading: false, sent: true });
                console.log(formData);
            });
    }    

    inputChangedHandler = (event, inputIdentifier) => {
        const updatedContactForm = {
            ...this.state.contactForm
        };
        const updatedFormElement = {
            ...updatedContactForm[inputIdentifier]
        };
        updatedFormElement.elementConfig.value = event.target.value;
        updatedFormElement.valid = checkValidity(updatedFormElement.elementConfig.value, updatedFormElement.validation);
        updatedFormElement.touched = true;
        updatedFormElement.validation.isToggled = !updatedFormElement.validation.isToggled;

        updatedContactForm[inputIdentifier] = updatedFormElement;

        let formIsValid = true;
        for ( let inputIdentifier in updatedContactForm) {
            formIsValid = updatedContactForm[inputIdentifier].valid && formIsValid;
        }
        this.setState({contactForm: updatedContactForm, formIsValid: formIsValid});
    }

    render () {
        const formElementsArray = [];
        for (let key in this.state.contactForm) {
            formElementsArray.push({
                id: key,
                config: this.state.contactForm[key]
            });
        }

        let form = (
            <form onSubmit={this.contactHandler} name="contact">
                {formElementsArray.map(formElement =>(
                    <Input 
                        key={formElement.id}
                        elementType={formElement.config.elementType}
                        containerClass={formElement.config.containerClass}
                        inputClass={formElement.config.inputClass}
                        elementConfig={formElement.config.elementConfig}
                        value={formElement.config.value}
                        invalid={!formElement.config.valid}
                        shoudValidate={formElement.config.validation}
                        touched={formElement.config.touched}
                        checked={formElement.config.validation.isToggled}
                        changed={(event) => this.inputChangedHandler(event, formElement.id)}
                        exited={(event) => this.inputChangedHandler(event, formElement.id)} /> 
                ))}
                <Button disabled={!this.state.formIsValid} />
            </form>
        );

        if (this.state.loading) { 
            form = <Spinner />
        }

        if (this.state.sent) { 
            form = <p id="contact-message" className="contact-message">Thank you for your message.<br /> We will respond as soon as possible.</p>
        }

        return (
            <div className="contact">
                <section id="contact-form" className="contact-form">
                    <h1>Contact</h1>
                    {form}      
                </section>
            </div>
        )
    }
};

export default ContactForm;

这是我的意见。js组件:

import React from 'react';
import { NavLink } from 'react-router-dom';

const input = ( props ) => {
    let label = <label htmlFor={props.elementConfig.htmlFor}>{props.elementConfig.label}</label>;
    let inputElement = null;
    let errorlabel = null;
    let inputClass = ['input'];
    const errorid = [props.elementConfig.id];

    if(props.invalid && props.shoudValidate && props.touched) {
        inputClass.push('error');
    }

    switch (props.elementType) {
        case ('input'):
            inputElement = <input 
                className ={inputClass.join(' ')}
                {...props.elementConfig.inputprops} 
                value={props.elementConfig.value}
                onChange={props.changed}
                onBlur={props.exited} />;            
            break;
        case ('email'):
            inputElement = <input 
                className ={inputClass.join(' ')}
                {...props.elementConfig.inputprops} 
                value={props.elementConfig.value}
                onChange={props.changed}
                onBlur={props.exited} />;            
            break;
        case ( 'textarea' ):
            inputElement = <textarea 
                className ={inputClass.join(' ')}
                {...props.elementConfig.inputprops} 
                value={props.elementConfig.value}
                onChange={props.changed}
                onBlur={props.exited} />;
            break;
        case ( 'checkbox' ):
            inputElement = <input 
                className ={[props.inputClass, inputClass.join(' ')].join(' ')}
                {...props.elementConfig.inputprops} 
                value={!props.checked}
                onChange={props.changed} />;
            label = <label htmlFor={props.elementConfig.htmlFor} className="custom-control-label">This form collects your name, e-mail, phone number, company name, and location so that we may correspond with you. Read our <NavLink to="/privacy" exact>privacy policy</NavLink> for more information. By submitting the form, you consent to have StackApp collect the listed information.</label>;
            break;
        default:
            inputElement = <input 
                className ={inputClass.join(' ')}
                {...props.elementConfig.inputprops} 
                value={props.elementConfig.value}
                onChange={props.changed}
                onBlur={props.exited} />;
    }

    if(props.invalid && props.touched) {
        errorlabel = <label id={errorid.join('-error')} className="error" htmlFor={props.elementConfig.htmlFor}>{props.elementConfig.invalid}</label>
    };

    let output = null;
    if(props.elementType === 'checkbox') {
        output = [inputElement, label, errorlabel];            
    } else {
        output = [label, inputElement, errorlabel];
    }

    return (
        <div role="group" className={props.containerClass}>
            {output}
        </div>
    )
};

export default input;

我错过了什么?

共有1个答案

陆翔飞
2023-03-14

即使formElementsArray。map似乎是最有可能的候选,但在本例中,它不是警告的来源。正如您在评论中提到的,每个键的构造都是唯一的。错误来自输入。js,在这里分配output=[inputElement,label,errorlabel]然后直接呈现{output}。React看到这是一个数组,但不知道它的大小是固定的,并希望数组中的每个元素都有一个唯一的属性。如果在输入元素标签错误标签上放置道具,则警告应消失。

 类似资料:
  • 问题内容: 这个问题需要一些假设的背景。让我们考虑一个有列的表,,,,使用MySQL作为RDBMS。由于如果给定的某个人的名字和出生日期与另一个人相同,那么根据定义,他们就是同一个人(除非有两个巧合,即我们两个人分别于1809年2月12日出生,他们叫亚伯拉罕·林肯),所以我们将上的唯一键,这意味着“不要将同一个人存储两次”。现在考虑以下数据: 如果现在尝试运行以下语句,则该语句应该并且将失败: 如

  • 我正在尝试我们非主键作为外键在我的应用程序。场景如下:我有EMPLOYEE和EMPLOYEE_PROPERTIES表。Employee和Employee属性之间存在一对多的关系。下面是我的架构: 下面是我的hibernate映射XML:------------------------------- -------------员工属性------------------- 是否可以引用非主键作为外键

  • 我使用uuidv4输入字段唯一的关键字,我甚至通过传递数组索引作为唯一的道具检查,但我得到相同的警告反应。StackOverflow上的一个类似问题建议在最外层的JSX标签上使用密钥,所以我将密钥放在

  • 所以我想渲染数组,但它一直在说,警告:列表中的每个孩子都应该有一个唯一的“键”道具,即使它有唯一的键,我的数组包含三个元素,它甚至没有正确渲染第三个数组,按钮没有甚至因为某种原因第三李的工作。 更新:我从firebase获得的数据如下所示: 此代码将选择每个数据的标题 当我将鼠标悬停在“fikka-fikka”上时,“fikka-fikka”的按钮甚至不起作用。在ed sheeran和一个方向上,

  • 得到一个警告:列表中的每个孩子都应该有一个唯一的“键”道具。我想不出我需要用哪把钥匙。 我红了反应指南,但它不能帮助我理解如何在我的情况下使用它

  • 问题内容: G’Day。我想遍历一堆JSON对象,然后将它们变成React Elements。对象看起来像这样 遍历它们的代码非常简单。这样: 而且我收到错误警告:数组或迭代器中的每个子代都应具有唯一的“键”属性。有什么提示吗?干杯 我更改了代码以执行此操作。 而且我得到同样的错误。我不明白为什么!固定!谢谢您的帮助。 这是代码。 问题答案: 您需要向React元素添加一个唯一的key prop。