javascript - 为什么我会收到关于在 React 中分配键的错误?

标签 javascript asp.net reactjs asp.net-core

我一直在研究 ReactJS demo for ASP.NET Core我正在为一条错误消息而苦苦挣扎:

Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of CommentList. See url for more information. in Comment (created by CommentList) in CommentList (created by CommentBox) in div (created by CommentBox) in CommentBox

信息很明确,数组的每个子项都需要一个键。然而,代码分配了一个键,并且下载了适用于 Chrome 的 React 控制台后,我还可以看到数组和添加的所有数据。

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

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赋值给评论组件,返回评论列表。 id 似乎不是 null,所以我很困惑为什么我仍然收到此错误消息。

可以帮我解决我哪里出错了吗?

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

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; }
    }
}

Controller /家庭 Controller

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 :)");
        }


    }
}

最佳答案

您也可以将 shortid 用于唯一键作为 id 的替代,这样即使您没有来自 json 的唯一 id,即使键也是唯一的。

var shortid = require('shortid');
function createNewTodo(text) {
  return {
    completed: false,
    id: shortid.generate(),
    text
  }
}

关于javascript - 为什么我会收到关于在 React 中分配键的错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51019359/

相关文章:

javascript - 返回的 AJAX html 中断 IE 点击事件

javascript - 如何删除对象数组中的两个重复值

javascript - 模式上的关闭图标停​​止工作

asyncpostbacktrigger 之后未调用 Javascript 函数

reactjs - 如何在 React Service Worker 中使用 process.env

javascript - 为什么 Javascript 允许非数字算术

c# - 在回发时保持滚动位置不起作用

c# - 使用数据绑定(bind)在 asp.net 中使用 optgroup 元素填充 HtmlSelect

npm - 使用带有 Bower 的 webpack

sockets - 用于计时器操作的 React/Redux 和 Websockets