如何使 React 组件可编辑?

How do I make a React component editable?

在我学习 React 和 firebase 的项目的最后阶段,我遇到了一个问题。通过阅读这两个文档,我了解了大部分的操作方法和操作。

我想从博客 post 中获取内容,然后对其进行编辑,然后使用

post 返回
update()

firebase 有方法。截至目前,我面临的两个错误是我无法编辑该内容,因为反应说它是一个受控元素,我从文档中了解到这是因为我将其作为值传入。

但是,当我尝试删除它并改为在 onInputChange 中创建一个 setState 时,就像文档建议的那样,它得到了更新,但内容空白,输入字段中也缺少原始文本。这意味着我做错了什么反应,但我不确定它是什么。

  constructor(props){
    super(props);
    this.state =  {
      title: '',
      body: '',
      post:{},
      
  };
    this.onInputChange = this.onInputChange.bind(this);
    this.onHandleUpdate = this.onHandleUpdate.bind(this);
}

  
  componentDidMount(){
    database.ref(`posts/${this.props.match.params.postId}`) 
    .on('value', snapshot => {
          this.setState({post: snapshot.val()});
    });
    this.postId= this.props.match.params.postId;
    
}
  onInputChange(e){
    this.setState({
       title: ‘’, body:''


    });
  }

  onHandleUpdate(e){
    console.log(this.postId);
    e.preventDefault();
    database.ref('posts').child(`${this.postId}`).update(this.state); 
    this.setState({
      title: '',
      body: ''    
    });
  }

  render() {
    return (
 
        <div className="container">
          <form onSubmit={this.onHandleUpdate}>
            <div className="form-group">
              <input value={this.state.title && this.state.post.title}  className="form-control" type="text" name="title" ref="title" onChange={this.onInputChange}/>
            </div>
              <br/>
            <div className="form-group">  
              <input value={this.state.body && this.state.post.body} className="form-control" type="text" name="body" ref="body" onChange={this.onInputChange} />
              <br/>
            </div>
            <button  className="btn btn-success">Submit</button>
          </form>
        </div>
      
    );
  }
    
    
    
}

这是目前代码的设置方式。 问题的总结归结为为什么我无法更改文本框中的值。请问我做错了什么?

由于它们是两个单独的字段值,您需要在两个单独的函数中处理它们。你不能用同样的方法onInputChange。您可以按以下方式更改您的代码。

constructor(props){
    super(props);
    this.state =  {
      post:{
             title: props.post.title || '',
             body: props.post.body|| '',
     },

  };

    this.onTitleChange = this.onTitleChange .bind(this);
    this.onBodyChange = this.onBodyChange .bind(this);
    this.onHandleUpdate = this.onHandleUpdate.bind(this);
}


  componentDidMount(){
    database.ref(`posts/${this.props.match.params.postId}`) 
    .on('value', snapshot => {
          this.setState({post: snapshot.val()});
    });
    this.postId= this.props.match.params.postId;

}
  onTitleChange(e){
    this.setState({

      post: { ...this.state.post,
       title: e.target.value}
    });
  }

  onBodyChange(e){
    this.setState({
      post: { ...this.state.post,
       body: e.target.value}
    });
  }

  onHandleUpdate(e){
    console.log(this.postId);
    e.preventDefault();
    database.ref('posts').child(`${this.postId}`).update(this.state); 
    this.setState({
      title: '',
      body: ''    
    });
  }

  render() {
    return (

        <div className="container">
          <form onSubmit={this.onHandleUpdate}>
            <div className="form-group">
              <input value={this.state.post.title}  className="form-control" type="text" name="title" ref="title" onChange={this.onTitleChange}/>
            </div>
              <br/>
            <div className="form-group">  
              <input value={this.state.post.body} className="form-control" type="text" name="body" ref="body" onChange={this.onBodyChange} />
              <br/>
            </div>
            <button  className="btn btn-success">Submit</button>
          </form>
        </div>

    );
  }

或者如果状态是从 componentDidMount 设置的,你的构造函数可能是这样的

constructor(props){
    super(props);
    this.state =  {
      post: null,  //hope you post contains title and body {title: 'sometitle', body: 'somebody'}
  };

如果您想在 React 中创建可编辑的受控输入,请创建具有值的输入以及更改该值的方法:

<input
 type="text"
 value={this.state.title}
 onChange={e => this.handleInputChange(e)}
/>

在上面的代码中,您定义了一对 onChange 处理程序,但您没有将事件传递给它们,因此它们永远没有任何数据可以使用。

对于我的示例,我的 onChange 处理程序可以是:

handleInputChange(e) {
    this.setState({
      title: e.target.value
    });
  }

每当我输入我的输入时,它都会改变组件的状态,这将改变我在输入中看到的内容。这有点间接,但这就是受控组件在反应中的工作方式。

如果您添加一个新的输入,那么您可以创建一个新的 onChange 处理程序,一切都应该正常工作。不过,这种方法很快就会变得复杂。创建一个包含 10 个输入的表单,突然间您的组件中有一大堆函数需要处理。

一种更易于管理的方法是创建一个适用于每个输入组件的 onChange 处理程序。您可以通过将要更新的状态字段的名称传递到函数中来创建它。

 handleChange(e, field) {
    this.setState({
      [field]: e.target.value
    });
  }

然后在你的输入中你可以像这样使用它:

<input
          type="text"
          value={this.state.title}
          onChange={e => this.handleChange(e, "title")}
        />

字段参数是您希望输入更新的字段名称的字符串。

这意味着您可以像这样对正文输入重复使用相同的方法:

  type="text"
  value={this.state.body}
  onChange={e => this.handleChange(e, "body")}
/>

您可以删除onTitleChange 和onBodyChange 方法,并替换为上面的handleChange 方法。简单多了。活动部件越少,损坏的东西就越少。

当您准备好提交表单时,您可以在 onHandleUpdate 方法中使用所需的状态值,如下所示:

onHandleUpdate(e){
    e.preventDefault();
    database.ref('posts').child(`${this.postId}`).update({
       title: this.state.title,
       body: this.state.body
    }); 
    this.setState({
      title: '',
      body: ''    
    });
  }

没有必要用 state 中的 post 值来完成整个嵌套操作。您可以随心所欲地嵌套,但在您仍在学习的同时,通过尽可能多地保持非嵌套状态,让事情易于推理。

database.ref(`posts/${this.props.match.params.postId}`) 
    .on('value', snap =>  this.setState({
       title: snap.val().title, 
       body: snap.val().body 
    }));

我制作了一个小沙箱来证明所有这些都有效。 Have a look at the hello component here。我稍微简化了它,我不得不替换数据库调用(因为我没有你的 firebase 密钥),但它应该是有意义的。

你可以用同样的方法处理变化

handleChange = (e) => {
    this.setState({
        [e.target.name]: e.target.value
    })
}