Почему я получаю ошибки о назначении ключей в React? - PullRequest
0 голосов
/ 25 июня 2018

Я работал с демоверсией 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 :)");
        }


    }
}

Ответы [ 4 ]

0 голосов
/ 25 июня 2018

Как предположили хорошие люди в этом вопросе, проблема была вызвана прописной буквой Id, установленной в handleCommentSubmit.

Был

handleCommentSubmit(comment) {
    comment.Id = comments.length + 1;
}

Изменить на

handleCommentSubmit(comment) {
    comment.id = comments.length + 1;
}

Путаница между прописными и строчными буквами была вызвана моим объявлением значений в моей модели, я записал их в верхнем регистре, однако результаты, возвращаемые ReactJS, конечно же, строчные.

0 голосов
/ 25 июня 2018

Вы также можете использовать shorttid для уникальных ключей в качестве альтернативы идентификатору, таким образом, даже если у вас нет уникального идентификатора из json, даже тогда ключ будет уникальным.

var shortid = require('shortid');
function createNewTodo(text) {
  return {
    completed: false,
    id: shortid.generate(),
    text
  }
}
0 голосов
/ 25 июня 2018

Ваши идентификаторы, вероятно, не уникальны. В большинстве случаев React не рекомендует использовать инкрементные идентификаторы. Идентификаторы используются в процессе сверки, см. Здесь: https://reactjs.org/docs/reconciliation.html#keys

Попробуйте использовать автора в качестве ключа, или, что еще лучше, попробуйте сгенерировать уникальные (с пакетом типа node-uuid, или посмотрите метод, представленный в @tarzen chugh его ответ.

0 голосов
/ 25 июня 2018

Используйте Id вместо id в качестве значения ключа, так как JavaScript учитывает регистр.Также добавьте .toString()

Идентификатор 'Id' устанавливается здесь:

comment.Id = comments.length + 1;

Обновлен код jsx:

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

Из документации React:

"Лучший способ выбрать ключ - использовать строку который однозначно идентифицирует элемент списка среди своих братьев и сестер. Чаще всего вы использовали бы идентификаторы из ваших данных в качестве ключей: "

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...