Я работал с демоверсией ReactJS для ASP.NET Core , и у меня возникает сообщение об ошибке:
Предупреждение: каждый дочерний элемент в массиве илиИтератор должен иметь уникальный ключ.Проверьте метод рендеринга CommentList
.Смотрите URL для получения дополнительной информации.in 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>
);
}
}
Вы можете видеть, что ключ назначен компоненту комментариев и возвращен в список комментариев.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')
);
Я использую модель для своих данных, так как я будупозже представим это в хранилище.
Models / CommentModel
namespace ReactDemo.Models
{
public class CommentModel
{
public int Id { get; set; }
public string Author { get; set; }
public string Text { get; set; }
}
}
Controllers / HomeController
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 :)");
}
}
}