首页 文章

ReactJS用于编辑注释

提问于
浏览
4

我正在试图弄清楚如何编辑ReactJS中的注释 . 我一直关注this tutorial .

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

  • 使用mutable state 而不是immutable 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 数据并使用最新数据更新 state . this.setState() 允许动态更新 . 旧的评论正在被新的评论所取代

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) 
     }); 
   },

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

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 用于保存输入的用户's input as it' . 我正在尝试使用编辑功能完成此操作 .

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

  • 监听服务器

  • 文本表单的作者字段 . 我们只需要文本字段

1 回答

  • 4

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

    在保存注释方面,您需要一个新的 endpoints 来处理该功能,它应该看起来几乎完全像 app.post('/api/comments') ,除了从读取文件获取 data 之外,它应该从 req.body 获取数据,这是发布给它的数据 . 要保持相同的URL this.props.url ,您可以将其设置为PATCH endpoints : app.patch('/api/comments' ...) . 我会把这个实现留给你 . React保存功能应该是这样的: Comment 组件应该使用state来管理它的状态 . 单击"Edit"应切换该状态以使 contentEditable 设置为true,"Edit"变为"Save"等 . 实际保存部分应在父组件 CommentBox 中定义,并应传递给 Comment 组件 . 这是一个基本的想法,你应该做出允许编辑的变化,它是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> 
         ); 
       } 
     });
    

相关问题