分析
用戶想要一個能夠顯示評論列表,并且允許用戶進行回復的組件。可能還需要支持多級回復,也就是對回復進行再回復。然后,我要考慮組件的結構和功能。
首先,數據結構方面,評論應該包含id、內容、作者、時間,以及可能的子回復。子回復的結構可能和評論類似,所以可以設計一個通用的結構,比如每個評論有一個replies數組,里面存放回復對象。
接下來是組件的狀態管理。評論列表應該用useState來管理,這樣當添加新評論或回復時,組件可以重新渲染。還需要處理用戶輸入,所以需要狀態來保存輸入的文本。
然后是UI部分。評論和回復可能需要遞歸渲染,因為每個回復下面可能還有更多的回復。所以可以考慮用一個遞歸組件來渲染評論及其子回復。每個評論項需要顯示作者、內容、時間,還有一個回復按鈕。點擊回復按鈕時,要顯示一個輸入框,讓用戶輸入回復內容。
輸入框部分,可能需要根據當前回復的父評論ID來判斷在哪里顯示輸入框。例如,當點擊某個評論的回復按鈕時,輸入框應該出現在該評論的下方。因此,需要有一個狀態來跟蹤當前正在回復的評論ID。
提交回復的函數需要處理兩種情況:一種是直接評論,另一種是回復某個具體的評論。提交時,需要更新評論列表,添加新的回復到對應的replies數組中。這里可能需要一個函數來遞歸查找父評論并添加回復,或者使用輔助函數來處理嵌套結構。
樣式方面,用戶可能希望有不同的縮進來表示層級關系。比如,頂級評論沒有縮進,一級回復縮進一定距離,二級回復再縮進更多,以此類推。可以用paddingLeft或者marginLeft來實現,根據層級動態調整。
還需要考慮組件的可定制性,比如允許用戶傳入自定義樣式、評論和回復的渲染方法,或者回調函數當提交評論時。這樣組件更靈活,用戶可以根據需要調整外觀和行為。
測試一下功能,比如添加評論、回復評論,確保狀態更新正確,UI渲染正確。特別是多級回復的情況,要確保遞歸渲染正確,并且輸入框出現在正確的位置。
能的優化點:使用useCallback來避免函數重復創建,提高性能。特別是提交回復的函數和回復按鈕的回調函數。另外,對于深層嵌套的評論,遞歸渲染可能會導致性能問題,但一般情況下的評論層級不會太深,所以應該可以接受。
最后,提供示例用法,讓用戶知道如何傳入初始數據,以及如何使用組件。可能需要提醒用戶根據需要調整樣式,或者處理時間格式化等問題,比如使用date-fns或其他庫來格式化時間顯示。
實現代碼
封裝一個可復用的評論回復組件,支持多級嵌套回復。以下是代碼實現:
import React, { useState } from 'react';
import PropTypes from 'prop-types';// 評論項組件
const CommentItem = ({ comment,depth = 0,onReply,activeReplyId,setActiveReplyId,parentAuthor
}) => {const maxDepth = 4; // 控制最大嵌套深度const canReply = depth < maxDepth;return (<div className="comment-item" style={{ marginLeft: depth * 32 }}><div className="comment-header"><span className="comment-author">{comment.author}</span>{parentAuthor && (<span className="reply-to">回復 @{parentAuthor}</span>)}<span className="comment-time">{comment.time}</span></div><div className="comment-content">{comment.content}</div>{canReply && (<button className="reply-btn"onClick={() => setActiveReplyId(comment.id)}>回復</button>)}{/* 回復輸入框 */}{activeReplyId === comment.id && (<CommentInputonSubmit={(content) => onReply(comment.id, content)}onCancel={() => setActiveReplyId(null)}/>)}{/* 遞歸渲染子回復 */}{comment.replies?.map((reply) => (<CommentItemkey={reply.id}comment={reply}depth={depth + 1}onReply={onReply}activeReplyId={activeReplyId}setActiveReplyId={setActiveReplyId}parentAuthor={comment.author}/>))}</div>);
};// 評論輸入框組件
const CommentInput = ({ onSubmit, onCancel }) => {const [content, setContent] = useState('');const handleSubmit = () => {if (content.trim()) {onSubmit(content);setContent('');}};return (<div className="comment-input-container"><textareavalue={content}onChange={(e) => setContent(e.target.value)}placeholder="輸入評論內容..."rows={3}/><div className="input-buttons"><button onClick={handleSubmit}>提交</button><button onClick={onCancel}>取消</button></div></div>);
};// 主組件
const CommentComponent = ({ initialComments,currentUser = '匿名用戶'
}) => {const [comments, setComments] = useState(initialComments);const [activeReplyId, setActiveReplyId] = useState(null);// 添加評論/回復const addComment = (content, parentId = null) => {const newComment = {id: Date.now(),author: currentUser,content,time: new Date().toLocaleString(),replies: []};if (!parentId) {setComments([...comments, newComment]);} else {const updateComments = (comments) => comments.map(comment => {if (comment.id === parentId) {return {...comment,replies: [...comment.replies, newComment]};}return {...comment,replies: updateComments(comment.replies)};});setComments(prev => updateComments(prev));}};return (<div className="comment-container"><CommentInput onSubmit={(content) => addComment(content)} /><div className="comments-list">{comments.map((comment) => (<CommentItemkey={comment.id}comment={comment}onReply={addComment}activeReplyId={activeReplyId}setActiveReplyId={setActiveReplyId}/>))}</div></div>);
};// Prop 類型校驗
CommentComponent.propTypes = {initialComments: PropTypes.arrayOf(PropTypes.shape({id: PropTypes.number.isRequired,author: PropTypes.string.isRequired,content: PropTypes.string.isRequired,time: PropTypes.string,replies: PropTypes.array})),currentUser: PropTypes.string
};export default CommentComponent;
組件特性說明:
- 核心功能:
- 支持多級嵌套回復(默認最多4層)
- 顯示回復對象(回復 @xxx)
- 支持自定義當前用戶
- 支持初始評論數據傳入
- 自動生成評論時間
- 組件結構:
CommentComponent
:主組件CommentItem
:單個評論項(支持遞歸渲染)CommentInput
:評論輸入組件
- 使用示例:
// 初始化數據示例
const initialComments = [{id: 1,author: '用戶A',content: '第一條評論',time: '2023-08-01 10:00',replies: [{id: 2,author: '用戶B',content: '第一條回復',time: '2023-08-01 10:05'}]}
];// 使用組件
<CommentComponent initialComments={initialComments}currentUser="當前用戶"
/>
- 樣式建議:
.comment-container {max-width: 800px;margin: 0 auto;padding: 20px;
}.comment-item {margin: 16px 0;padding: 12px;border: 1px solid #eee;border-radius: 4px;
}.comment-header {display: flex;align-items: center;margin-bottom: 8px;color: #666;
}.comment-author {font-weight: bold;margin-right: 8px;
}.reply-to {color: #999;margin-right: 8px;
}.comment-time {font-size: 0.9em;
}.reply-btn {background: none;border: none;color: #1890ff;cursor: pointer;padding: 4px 8px;
}.comment-input-container {margin: 16px 0;
}.comment-input-container textarea {width: 100%;padding: 8px;margin-bottom: 8px;
}.input-buttons button {margin-right: 8px;padding: 4px 12px;
}
- 擴展建議:
- 增加點贊功能
- 支持富文本輸入
- 添加評論刪除功能
- 支持用戶頭像顯示
- 增加評論加載更多功能
- 支持@用戶功能
使用時請根據實際需求調整樣式和功能實現,可以通過props傳遞更多配置項(如最大嵌套深度、日期格式等)來增強組件的靈活性。