首页 > 解决方案 > 为什么我会收到有关在 React 中分配键的错误?

问题描述

我一直在研究ASP.NET Core 的 ReactJS 演示,但我遇到了一条错误消息:

警告:数组或迭代器中的每个孩子都应该有一个唯一的“key”道具。检查CommentList. 查看网址了解更多信息。在 Comment(由 CommentList 创建)在 CommentList(由 CommentBox 创建)在 div(由 CommentBox 创建)在 CommentBox

信息很明确,数组的每个孩子都需要一个键。但是,代码分配了一个键,并且下载了 Chrome 的反应控制台后,我还可以看到数组和添加的所有数据。

在我的代码中,我有以下内容:

class CommentList extends React.Component {
    render() {
        const commentNodes = this.props.data.map(comment => (
            <Comment author={comment.author} key={comment.id}>
                {comment.author}
            </Comment>
        ));
        return (
            <div className="commentList">
                {commentNodes}
            </div>
        );
    }
}

可以看到key被赋值给了comment组件,并返回到了comment列表中。似乎不是空的id,所以我对为什么仍然收到此错误消息感到困惑。

可以帮助我解决这个问题吗?

到目前为止,这是我的完整源代码:

js/app.jsx

class CommentBox extends React.Component {
    constructor(props) {
        super(props);
        this.state = { data: [] };
        this.handleCommentSubmit = this.handleCommentSubmit.bind(this);
    }

    loadCommentsFromServer() {
        const xhr = new XMLHttpRequest();
        xhr.open('get', this.props.url, true);
        xhr.onload = () => {
            const data = JSON.parse(xhr.responseText);
            this.setState({ data: data });
        };
        xhr.send();
    }
    handleCommentSubmit(comment) {
        const comments = this.state.data;
        // Optimistically set an id on the new comment. It will be replaced by an
        // id generated by the server. In a production application you would likely
        // use a more robust system for ID generation.
        comment.Id = comments.length + 1;
        const newComments = comments.concat([comment]);
        this.setState({ data: newComments });

        const data = new FormData();
        data.append('author', comment.author);
        data.append('text', comment.text);

        const xhr = new XMLHttpRequest();
        xhr.open('post', this.props.submitUrl, true);
        xhr.onload = () => this.loadCommentsFromServer();
        xhr.send(data);
    }
    componentDidMount() {
        this.loadCommentsFromServer();
        window.setInterval(() => this.loadCommentsFromServer(), this.props.pollInterval);
    }
    render() {
        return (
            <div className="commentBox card">
                <h4>Comments</h4>
                <CommentList data={this.state.data} />
                <CommentForm onCommentSubmit={this.handleCommentSubmit} />
            </div>
        );
    }
}
class CommentList extends React.Component {
    render() {
        const commentNodes = this.props.data.map(comment => (
            <Comment author={comment.author} key={comment.id}>
                {comment.author}
            </Comment>
        ));
        return (
            <div className="commentList">
                {commentNodes}
            </div>
        );
    }
}

class CommentForm extends React.Component {
    constructor(props) {
        super(props);
        //Initial state?
        this.state = { author: '', text: '' };
        //Event handlers
        this.handleAuthorChange = this.handleAuthorChange.bind(this);
        this.handleTextChange = this.handleTextChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleAuthorChange(e) {
        this.setState({ author: e.target.value });
    }
    handleTextChange(e) {
        this.setState({ text: e.target.value });
    }
    handleSubmit(e) {
        e.preventDefault();
        const author = this.state.author.trim();
        const text = this.state.text.trim();
        //If inputs are null then return nothing.
        if (!text || !author) {
            return;
        }
        //Post data to the server
        this.props.onCommentSubmit({ author: author, text: text });
        //Clear form
        this.setState({ author: '', text: '' });
    }

    render() {
        return (
            <div className="commentForm">
                <form className="commentForm" onSubmit={this.handleSubmit}>
                    <input type="text" placeholder="Your name" value={this.state.author} onChange={this.handleAuthorChange} />
                    <input type="text" placeholder="Say something..." value={this.state.text} onChange={this.handleTextChange} />
                    <input type="submit" value="Post" />
                </form>
            </div>
        );
    }
}
class Comment extends React.Component {
    render() {
        return (
            <div className="comment">
                <p className="commentAuthor">
                    {this.props.author}
                </p>
            </div>
        );
    }
}

ReactDOM.render(
    <CommentBox url="/comments" submitUrl="/comments/new" pollInterval={2000} />,
    document.getElementById('content')
);

我正在为我的数据使用模型,因为稍后我将把它引入存储库。

型号/评论型号

namespace ReactDemo.Models
{
    public class CommentModel
    {
        public int Id { get; set; }
        public string Author { get; set; }
        public string Text { get; set; }
    }
}

控制器/家庭控制器

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using ReactDemo.Models;

namespace ReactDemo.Controllers
{
    public class HomeController : Controller
    {
        private static readonly IList<CommentModel> _comments;
        static HomeController()
        {
            _comments = new List<CommentModel>
            {
                new CommentModel
                {
                    Id = 1,
                    Author = "Daniel Lo Nigro",
                    Text = "Hello ReactJS.NET World!"
                },
                new CommentModel
                {
                    Id = 2,
                    Author = "Pete Hunt",
                    Text = "This is one comment"
                },
                new CommentModel
                {
                    Id = 3,
                    Author = "Jordan Walke",
                    Text = "This is *another* comment"
                },
            };
        }
        public IActionResult Index()
        {
            return View();
        }
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
        [Route("comments")]
        [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
        public ActionResult Comments()
        {
            return Json(_comments);
        }
        [Route("comments/new")]
        [HttpPost]
        public ActionResult AddComment(CommentModel comment)
        {
            // Create a fake ID for this comment
            comment.Id = _comments.Count + 1;
            _comments.Add(comment);
            return Content("Success :)");
        }


    }
}

标签: javascriptasp.netreactjsasp.net-core

解决方案


使用Id而不是id作为您的键值,因为 javascript 区分大小写。还添加.toString()

'Id' 在这里设置:

comment.Id = comments.length + 1;

更新了 jsx 代码:

<Comment author={comment.author} key={comment.Id.toString()}> {comment.author} </Comment> ));

来自 React 文档:

“选择键的最佳方法是使用一个字符串,该字符串在其兄弟项中唯一标识一个列表项。大多数情况下,您会使用数据中的 ID 作为键:”


推荐阅读