簡體   English   中英

ReactDOM 只渲染一個組件

[英]ReactDOM renders only one component

我想創建一個具有評論功能的應用程序。 我正在嘗試這樣的代碼:

response.data.forEach((el, idx, arr) => {
  const newMessage = <CommentMessage username={el.username} message={el.message}/>
  ReactDOM.render(newMessage, this.commentListRef.current)
})

我正在使用 MySQL。 Axios 用於 HTTP 請求。 而Next.js為框架。

完整代碼:

import React from 'react'
import ReactDOM from 'react-dom'
import styles from './comments-list.module.css'

class CommentMessage extends React.Component {
    constructor(props) {
        super(props)
    }
    render() {
        return (<div>
            <b>{this.props.username}</b>
            <span>: </span>
            <span>{this.props.message}</span>
        </div>)
    }
}

class CommentsList extends React.Component {
    constructor(props) {
        super(props)

        this.commentListRef = React.createRef()

        const comments = []
    }
    loadComments() {
        const axios = require('axios')
        axios.get('/api/getcomments')
            .then(response => {
                response.data.forEach((el, idx, arr) => {
                    const newMessage = <CommentMessage username={el.username} message={el.message}/>
                    ReactDOM.render(newMessage, this.commentListRef.current)
                })
            })
            .catch(err => {
                console.log(err)
            })
    }
    render() {
        return (<div ref={this.commentListRef} onLoad={this.loadComments()}>

        </div>)
    }
}

export default CommentsList

但它只呈現這個:

在此處輸入圖像描述

期待這個:

在此處輸入圖像描述

你的做法很奇怪; 我不知道這是不是故意的。 無論如何,推薦的方法是將評論存儲為組件的 state 的一部分,並在收到評論時更新 state。

像這樣:

class CommentsList extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
          comments: []
        };

        this.commentListRef = React.createRef()

        const comments = []
    }
    loadComments() {
        const axios = require('axios')
        axios.get('/api/getcomments')
            .then(response => {
              this.setState({
                comments: response.data
              });
            })
            .catch(err => {
                console.log(err)
            })
    }
    
    componentDidMount(){
      this.loadComments();
    }
    
    render() {
        return (<div ref={this.commentListRef}>
            (this.state.comments.map(comment => (
                <CommentMessage username={comment.username} message={comment.message}/>
            )))
        </div>)
    }
}

此外,您的 onLoad 沒有按預期工作。 每次組件呈現時它都會調用 loadComments,我什至不知道 onLoad 是否是 div 上的正確事件。

無論如何,如果您絕對想按照自己的方式進行操作,則必須將每個節點安裝到其自己的容器中。 正如您現在所擁有的,每條評論都覆蓋了commentListRef 的內容。 因此,您必須創建一個新元素 append 到 commentListRef,並將反應組件安裝到該元素:


   loadComments() {
       const axios = require('axios')
       axios.get('/api/getcomments')
           .then(response => {
               response.data.forEach((el, idx, arr) => {
                   const element = document.createElement('div');
                   this.commentListRef.current.appendChild(element);
                   const newMessage = <CommentMessage username={el.username} message={el.message}/>
                   ReactDOM.render(newMessage, element)
               })
           })
           .catch(err => {
               console.log(err)
           })
   }

ReactDOM.render只會為給定容器渲染一個組件。 文檔

首次調用時,內部的任何現有 DOM 元素都會被替換。 后面的調用使用 React 的 DOM diffing 算法進行有效更新。

基本上,當您在循環中調用ReactDOM.render時,React 將每個給定組件視為對前一個組件的更新,而不是單獨渲染每個組件。

最佳實踐是在根容器(通常稱為<App> )呈現單個組件。 但是,您似乎已經這樣做了,因為這些ReactDOM.render調用正在另一個組件中發生。 通常,您應該只需要在應用程序中使用ReactDOM.render一次。

相反,您可以將數據存儲在CommentsList組件的 state 中,然后從父組件的render方法中返回子組件。

例如:

class CommentsList extends React.Component {
    constructor(props) {
        super(props)
        
        this.state = {
            comments: [],
        }
    }

    loadComments = () => {
        const axios = require('axios')
        axios.get('/api/getcomments')
            .then(response => {
                this.setState(prev => ({...prev, comments: response.data}));
            })
            .catch(err => {
                console.log(err)
            })
    }
    
    render() {
        const { comments } = this.state;
        
        return (
            <React.Fragment>
                {comments.map(e => (
                    <CommentMessage key={e.id} username={e.username} message={e.message}/>
                ))}
            </React.Fragment>
        )
    }
}

注意:我還向CommentMessage組件傳遞了一個key ,以便為每個孩子提供一個穩定的身份(有關更多信息,請參閱文檔)。 不得不猜測,但我假設評論會有一個id值,如果沒有,您可以為評論選擇一個不同的唯一值作為鍵。

此外,我建議將基於類的組件遷移到React Hooks ——一旦你掌握了鈎子,使用起來會更容易。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM