【问题标题】:ReactJS for editing commentsReactJS 用于编辑评论
【发布时间】:2016-05-21 08:40:11
【问题描述】:

我试图弄清楚如何在 ReactJS 中编辑 cmets。我一直在关注this tutorial

我对解决方案有几种理论:

  • 使用可变的state 而不是不可变的props
  • 与具有loadCommentsFromServerhandleCommentSubmit 函数的CommentBox 组件有关。 loadComments 函数会触发 AJAX 请求,可能发送到我的 comments.json 文件。

这是来自server.js 文件的相关代码

var COMMENTS_FILE = path.join(__dirname, 'comments.json'); 

app.get('/api/comments', function(req, res) { 
   fs.readFile(COMMENTS_FILE, function(err, data) { 
     if (err) { /* Print error to console */ } 
     res.json(JSON.parse(data)); 
   }); 
 }); 

// This snippet of code is probably the most important
 app.post('/api/comments', function(req, res) { 
   fs.readFile(COMMENTS_FILE, function(err, data) { 
     if (err) { /* Print error to console */ }
     var comments = JSON.parse(data); 

     var newComment = { 
       id: Date.now(), 
       text: req.body.text, 
     }; 
     comments.push(newComment); 
     fs.writeFile(COMMENTS_FILE, JSON.stringify(comments, null, 4), function(err) { 
       if (err) { /* Print error to console */ }
       res.json(comments); 
     }); 
   }); 
 }); 

这是我生成反应组件的主要脚本文件

var Comment = React.createClass({ 

   render: function() { 
     return ( 
       <div className="comment"> 
         // Trying to change the value of the text box on edit
         <p onChange={this.handleTextChange()}> {this.props.text} </p> 
       </div> 
     ); 
   } 
 }); 

 var CommentBox = React.createClass({

第一次创建组件时,我们需要从服务器获取JSON的数据,并用最新的数据更新statethis.setState() 允许动态更新。旧的 cmets 数组正在被新数组替换

   loadCommentsFromServer: function() { 
     $.ajax({ 
       url: this.props.url, 
       dataType: 'json', 
       cache: false, 
       success: function(data) { 
         this.setState({data: data}); 
       }.bind(this), 
       error: function(xhr, status, err) { 
         console.error(this.props.url, status, err.toString()); 
       }.bind(this) 
     }); 
   }, 

此函数将数据从子组件传递到父组件。它应该提交到服务器并刷新 cmets 列表

   handleCommentSubmit: function(comment) { 
     var comments = this.state.data; 
     comment.id = Date.now(); 
     var newComments = comments.concat([comment]); 
     this.setState({data: newComments}); 
     $.ajax({ 
       url: this.props.url, 
       dataType: 'json', 
       type: 'POST', 
       data: comment, 
       success: function(data) { 
         this.setState({data: data}); 
       }.bind(this), 
       error: function(xhr, status, err) { 
         this.setState({data: comments}); 
         console.error(this.props.url, status, err.toString()); 
       }.bind(this) 
     }); 
   }, 
   getInitialState: function() { 
     return {data: []}; 
   }, 
   componentDidMount: function() { 
     this.loadCommentsFromServer(); 
     setInterval(this.loadCommentsFromServer, this.props.pollInterval); 
   }, 
   render: function() { 
     return ( 
       <div className="commentBox"> 
         <h1>Comments</h1> 
         <CommentList data={this.state.data} /> 
         <CommentForm onCommentSubmit={this.handleCommentSubmit} /> 
       </div> 
     ); 
   } 
 }); 

 var CommentList = React.createClass({ 
   render: function() { 
     var commentNodes = this.props.data.map(function(comment) { 
       return <Comment key={comment.id}>{comment.text}</Comment>  
     }); 
     return <div className="commentList"> {commentNodes} </div> 
     ); 
   } 
 }); 

这里正在创建一个用于填写表单的组件。 this.state 用于保存用户输入的内容。我正在尝试使用编辑功能来完成此操作。

 var CommentForm = React.createClass({ 
   getInitialState: function() { 
     return {text: ''}; 
   }, 
   handleTextChange: function(e) { 
     this.setState({text: e.target.value}); 
   }, 
   // This is also probably an important function
   handleSubmit: function(e) { 
     e.preventDefault(); 
     var text = this.state.text.trim(); 
     this.props.onCommentSubmit({text: text}); 
     this.setState({text: ''}); 
   }, 

输入元素的value 属性将反映组件的状态并将onChange 处理程序附加到它们

   render: function() { 
     return ( 
       <form className="commentForm" onSubmit={this.handleSubmit}> 
         <input type="text" value={this.state.text} onChange={this.handleTextChange} /> 
         <input type="submit" value="Post" /> 
       </form> 
     ); 
   } 
 }); 

最后,我正在渲染CommentBox 组件。 url 属性从服务器获取动态数据。 pollInterval 每 2 秒重新加载一次页面。

 ReactDOM.render( 
   <CommentBox url="/api/comments" pollInterval={2000} />, 
   document.getElementById('content') 
 ); 

这是我对如何实现编辑功能的想法

setTimeout(function() {
    $('.edit').on('click', function() {
        $(this).prev().prop('contentEditable', 'true');
        $(this).prev().focus();
    });
},1000);

我不得不使用setTimeout,因为加载组件文件需要一些时间。然后我会监听点击编辑按钮,并将 html5 contentEditable 属性更改为 true。

我遇到的问题是在编辑 JSON 文件后更新更改。

我也想知道是否有更快速的方式来完成这个 onclick 功能

正如您在我的组件文件中看到的,我在呈现文本正文的段落中添加了一个 onChange 处理程序。

render: function() { 
  return ( 
    <div className="comment"> 
      <p onChange={this.handleTextChange()}> {this.props.text} </p> 
    </div>  
  ); 
}  

我在互联网上广泛搜索了编辑功能的示例,但找不到任何东西。

我的目标是让这段代码尽可能地可读。我试图减少与手头问题没有直接关系的代码。我删除了以下代码:

  • npm 变量声明和app.use
  • 服务器的监听
  • 文本表单的作者字段。我们只需要文本字段

【问题讨论】:

  • 关于如何改进这篇文章的任何建议?我只想拥有相关信息,这样最容易解决问题
  • 您的实际问题是什么?您有许多代码和文本块,但在任何地方都看不到一个问号。如果您在某处遇到问题,请明确说明问题所在。

标签: javascript jquery reactjs components


【解决方案1】:

让 jQuery 与 React 组件混搭通常不是一个好主意(尽管 jQuery + React 可以在某些任务上相互配合);我们正在运行一个大规模的 React 应用程序,并且从早期开始就已经花费了很多时间来删除这个实例。

在保存 cmets 方面,您需要一个新的端点来处理该功能,它应该看起来几乎与 app.post('/api/comments') 完全一样,除了不是从读取文件中获取 data,它应该从 req.body 获取数据,这是发布给它的数据。要保持相同的 URL this.props.url,您可以将其设置为 PATCH 端点:app.patch('/api/comments' ...)。我将把实现留给你。 React 的保存功能应该是这样的:Comment 组件应该使用状态来管理它的...状态。单击“编辑”应切换该状态以将contentEditable 设置为true,“编辑”变为“保存”等。实际保存部分应在父组件CommentBox 中定义,并应传递给@ 987654329@ 组件。这是您应该进行的更改以允许编辑的基本想法,它 100% 未经测试,但希望对您有所帮助。

// changes to Comment component
var Comment = React.createClass({
  getInitialState: function() {
    return {
      contentEditable: false,
      buttonText: 'Edit',
      text: this.props.text
    };
  },
  handleButton: function() {   
    var commentTag = this.refs.comment;
    // if the component is currently editable and the text is different from the original, save it
    if (this.state.contentEditable && commentTag.textContent != this.state.text) {
      this.props.onUpdateComment(this.props.id, commentTag.textContent);
    }
    // invert current contentEditable state Save => Edit or Edit => Save
    var editable = !this.state.contentEditable;
    this.setState({
      contentEditable: editable,
      // update the state to reflect the edited text
      text: commentTag.textContent,
      // change button text based on editable state
      buttonText: editable ? 'Save' : 'Edit'
    });
 },
 render: function() {
   return (
     <div className="comment">
       <h2 className="commentAuthor">{this.props.author}</h2>
       <p ref="comment" contentEditable={this.state.contentEditable}>{this.state.text}</p>
       <button onClick={this.handleButton}>{this.state.buttonText}</button>
     </div>
   );
 }
});

// changes to CommentList
var CommentList = React.createClass({ 
   render: function() { 
     var commentNodes = this.props.data.map(function(comment) { 
       return <Comment onUpdateComment={this.props.onUpdateComment} {...comment} />  
     }); 
     return ( 
       <div className="commentList"> 
         {commentNodes} 
       </div> 
     ); 
   } 
 });

 // changes to CommentBox
 var CommentBox = React.createClass({
   loadCommentsFromServer: function() {
     $.getJSON(this.props.url)
      .then(function(newComments) {
        this.setState({ data: newComments });
      }.bind(this))
      .fail(function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      });
   }, 
   handleCommentSubmit: function(comment) { 
     var comments = this.state.data; 
     comment.id = Date.now(); 
     var newComments = comments.concat([comment]); 
     this.setState({data: newComments}); 

     $.post(this.props.url, comments)
      .then(function(data) {
        this.setState({ data: data });
      }.bind(this))
      .fail(function(xhr, status, err) {
        this.setState({ data: comments });
        console.error(this.props.url, status, err.toString());
      }.bind(this));
   },
   onUpdateComment: function(id, comment) {
     // clone state, we don't want to alter this directly
     var newData = this.state.data.slice(0);
     newData.forEach(function(item) {
       if(item.id === id) {
         item.text = comment;
       }
     });
     $.ajax({
       url: this.props.url,
       dataType: 'json',
       method: 'PATCH',
       data: newData
     }).then(function(data) {
       this.setState({ data: data });
     }.bind(this));
   },
   getInitialState: function() { 
     return {data: []}; 
   }, 
   componentDidMount: function() { 
     this.loadCommentsFromServer(); 
     setInterval(this.loadCommentsFromServer, this.props.pollInterval); 
   }, 
   render: function() { 
     return ( 
       <div className="commentBox"> 
         <h1>Comments</h1> 
         <CommentList data={this.state.data} /> 
         <CommentForm onCommentSubmit={this.handleCommentSubmit} /> 
       </div> 
     ); 
   } 
 }); 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-10
    • 1970-01-01
    • 2022-07-13
    • 1970-01-01
    • 1970-01-01
    • 2015-08-16
    • 2016-12-23
    • 2012-11-18
    相关资源
    最近更新 更多