我想创建一个带有评论功能的应用。我正在尝试使用这样的代码:
response.data.forEach((el, idx, arr) => {
const newMessage = <CommentMessage username={el.username} message={el.message}/>
ReactDOM.render(newMessage, this.commentListRef.current)
})
我正在使用 MySQL。用于 HTTP 请求的 Axios。以及用于框架的 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
但它只呈现这个:
预期:
答案 0 :(得分:0)
你对这件事的看法很奇怪;不知道是不是故意的无论如何,推荐的方法是将评论存储为组件状态的一部分,并在收到评论时更新状态。
像这样:
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 的内容。因此,您必须创建一个新元素,将其附加到 commentListRef,并将 react 组件安装到该元素上:
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)
})
}
答案 1 :(得分:0)
ReactDOM.render
只会为给定的容器渲染一个组件。来自the docs:
第一次调用时,任何现有的 DOM 元素都会被替换。之后的调用使用 React 的 DOM diffing 算法进行高效更新。
基本上,当您在循环中调用 ReactDOM.render
时,React 会将每个给定组件视为对前一个组件的更新,而不是单独呈现每个组件。
最佳实践是在根容器(通常称为 <App>
)处渲染单个组件。但是,您似乎已经这样做了,因为这些 ReactDOM.render
调用发生在另一个组件中。通常,您只需在应用内使用 ReactDOM.render
一次。
相反,您可以将数据存储在 CommentsList
组件的状态中,然后从父级的 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>
)
}
}
注意:我还向 key
组件传递了一个 CommentMessage
,以便为每个孩子提供一个稳定的身份(有关详细信息,请参阅 docs)。不得不猜测,但我假设评论会有一个 id
值,如果没有,您可以为评论选择不同的唯一值以用作键。
此外,我建议您转向 React Hooks 而不是基于类的组件——一旦您掌握了钩子,就会更容易使用。