【问题标题】:How to set defaultValue, value={this.props.value}, and update the value of a text input with React?如何设置 defaultValue,value={this.props.value},并使用 React 更新文本输入的值?
【发布时间】:2016-05-15 18:45:39
【问题描述】:

总结:

我正在尝试使用 React 创建博客,但似乎在设置和更新文本字段时遇到了障碍。我有来自数据库的博客文本和用户名,并希望在给定用户的文本窗口中设置博客文本。然后,当用户键入时,我也想更新该文本。

尝试:

如果我设置我的 textarea 值={this.props.name},它将正确设置值但不会更新。如果我将它设置为使用{this.state.value} 更新,那么它会从空白开始,但会正确更新。我可以找到有关如何设置默认值或更新值的示例。我无法弄清楚如何做到这两点。提前谢谢你。

应用内的 ClickScreen React 组件调用

<ClickScreen
    setClicks={this.setClicks}
    setUsername={this.setUsername}
    setBlog={this.setBlog}
    onLogout={this.onLogout}
    counter={this.state.counter}
    blogtext={this.state.blogtext}
    username={this.state.username}
/>

ClickScreen 页面中的 BlogEntry React 组件调用:

<EditBlog name={this.props.blogtext} username={this.props.username} ></EditBlog>

EditBlog React 组件

// Allows a user to edit a blog entry.
var EditBlog = React.createClass({
  displayName: 'Editor',
  propTypes: {
    name: React.PropTypes.string.isRequired
  },
  getInitialState: function() { 
    console.log("getInitialState value: " + this.props.name);
    return {
      value: this.props.name,
    };
  },
  componentDidMount: function() {
         this.setState({value: this.props.name});
  },
  handleChange: function(event) {
    console.log("changing the text area to: " + event.target.value)
    this.setState({value: event.target.value});
  },
  updateBlogText: function() {
        ajax('update_blog.php', { blogtext: this.value, username: this.props.username }, function(response) {
            console.log("Updating blog text to: " + this.state.value + " with user: " + this.props.username);
            
            if (response.result === 'success') {
                console.log("Success!");
                //this.props.setClicks(response.counter, response.username, response.blogtext);
                //this.props.setUsername(response.username);
                //this.props.setBlog(response.blogtext);
            }
            else if (response.result === 'error') {
                alert('Error: ' + response.msg);
                console.log("Error!");
            }
            else {
                alert('Response message has no result attribute.');
            }
        }.bind(this));
        console.log("Click button clicked");
    },
  render: function() {
    console.log("this.state.value: " + this.state.value)
    console.log("this.state.value blogtext: " + this.props.name);
    this.state.value = this.props.value;
    return (
        <div>
            <h2>Blog Entry</h2>
            <center>
              <form id="noter-save-form" method="POST">
                <textarea id="noter-text-area" name="textarea"  onChange={this.handleChange} defaultValue={this.props.name}></textarea>
                <input type="submit" value="Save" onClick={this.updateBlogText}/>
              </form>
            </center>
        </div>
    );
  }
});

更新: 在我理解受控和不受控的 React 组件和 React 生命周期之间存在一些问题。现在该值在 getInitialState 中设置,然后在 componentWillReceiveProps 中适当更新。谢谢大家!

变化:

  • componentDidMount -> componentWillReceiveProps。这与 React 组件生命周期有关。
  • 文本区域defaultValue={this.props.name} 已更改以反映value={this.state.value} 的更新状态值。
  • 渲染函数中的this.state.value=this.props.value 已被移除。
       // Allows a user to edit a blog entry.
        var EditBlog = React.createClass({
          displayName: 'Editor',
          propTypes: {
                name: React.PropTypes.string.isRequired
          },
          getInitialState: function() { 
            console.log("getInitialState value: " + this.props.name);
            return {
                value: this.props.name,
            };
          },
          componentWillReceiveProps: function(nextProps) {
                console.log("componentWillReceiveProps: " + nextProps.name);
                this.setState({value: nextProps.name});
          },
          handleChange: function(event) {
                console.log("changing the text area to: " + event.target.value);
                this.setState({value: event.target.value});
          },
          updateBlogText: function() {
                ajax('update_blog.php', { blogtext: this.value, username: this.props.username }, function(response) {
                    console.log("Updating blog text to: " + this.state.value + " with user: " + this.props.username);
                    
                    if (response.result === 'success') {
                        console.log("Success!");
                        //this.props.setClicks(response.counter, response.username, response.blogtext);
                        //this.props.setUsername(response.username);
                        //this.props.setBlog(response.blogtext);
                    }
                    else if (response.result === 'error') {
                        alert('Error: ' + response.msg);
                        console.log("Error!");
                    }
                    else {
                        alert('Response message has no result attribute.');
                    }
                }.bind(this));
                console.log("Click button clicked");
            },
          render: function() {
            return (
                <div>
                    <h2>Blog Entry</h2>
                    <center>
                      <form id="noter-save-form" method="POST">
                        <textarea id="noter-text-area" name="textarea"  onChange={this.handleChange} value={this.state.value}></textarea>
                        <input type="submit" value="Save" onClick={this.updateBlogText}/>
                      </form>
                    </center>
                </div>
            );
          }
        });

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    所以,无论何时你想编辑 props,你都必须将它们设置为本地组件状态(就像你在 getInitialState 中通过设置 props 的值一样)。道具是不可变的,因此将输入的值或 defaultValue 设置为道具将/不应该允许您更改道具。

    所以在下面,我所做的是设置 this.state.name 的输入值,并且 this.state.name 在初始状态下设置为 this.props.name,每当您调用 update 时,它​​都会更新组件状态与输入中键入的任何内容。

    如果您需要将名称传递回父组件,那么您需要从父组件传入一个函数,然后您可以从子组件调用该函数以通知父组件名称值已更改,然后父组件将需要更新名称,然后将其传递回子级...这将创建 2 路数据绑定..

    // Allows a user to edit a blog entry.
    var EditBlog = React.createClass({
      displayName: 'Editor',
      propTypes: {
        name: React.PropTypes.string.isRequired
      },
      getInitialState: function() { 
        console.log("getInitialState value: " + this.props.name);
        return {
          value: this.props.name,
        };
      },
      componentWillReceiveProps: function ( newProps ) {
        this.setState( { value:newProps.name } );
      }
      handleChange: function(event) {
        console.log("changing the text area to: " + event.target.value)
        this.setState({value: event.target.value});
      },
      updateBlogText: function() {
            ajax('update_blog.php', { blogtext: this.value, username: this.props.username }, function(response) {
                console.log("Updating blog text to: " + this.state.value + " with user: " + this.props.username);
    
                if (response.result === 'success') {
                    console.log("Success!");
                    //this.props.setClicks(response.counter, response.username, response.blogtext);
                    //this.props.setUsername(response.username);
                    //this.props.setBlog(response.blogtext);
                }
                else if (response.result === 'error') {
                    alert('Error: ' + response.msg);
                    console.log("Error!");
                }
                else {
                    alert('Response message has no result attribute.');
                }
            }.bind(this));
            console.log("Click button clicked");
        },
      render: function() {
        console.log("this.state.value: " + this.state.value)
        console.log("this.state.value blogtext: " + this.props.name);
        this.state.value = this.props.value;
        return (
            <div>
                <h2>Blog Entry</h2>
                <center>
                  <form id="noter-save-form" method="POST">
                    <textarea id="noter-text-area" name="textarea"  onChange={this.handleChange} value={value}></textarea>
                    <input type="submit" value="Save" onClick={this.updateBlogText}/>
                  </form>
                </center>
            </div>
        );
      }
    });
    

    【讨论】:

    • 这是一个很好的解释。非常感谢你。我唯一需要对您的代码进行修改的是对价值的调用。相反,我需要将文本区域设置为 value={this.state.value} 并删除 `this.state.value = this.props.value;. Once I did that the state was updating correctly in componentWillReceiveProps`。我不明白受控组件和不受控组件之间的区别。谢谢。
    【解决方案2】:

    对于 React 中的表单:

    defaultValue 和 defaultChecked 属性仅在初始渲染期间使用。如果需要在后续渲染中更新值,则需要使用受控组件。

    Docs on controlled components

    【讨论】:

    • 谢谢你。我不明白受控组件和不受控组件之间的区别。
    【解决方案3】:

    阅读您的代码,无需:

    componentDidMount: function() {
        this.setState({value: this.props.name});
    },
    

    getInitialState 已经完成了这项工作。如果您打算在组件收到新道具时更新状态,您应该编写:

    componentWillReceiveProps: function(nextProps) {
        this.setState({value: nextProps.name});
    },
    

    我认为,在您的情况下,您应该使用 this.state.value 并且它没有很好地初始化,因为当接收到与 undefined 不同的 props.name 值时,没有实现 componentWillReceiveProps 来更新组件状态。

    【讨论】:

    • 谢谢!您和@fayzaan 都正确地将componentDidMount 更改为componentWillReceiveProps。我将回顾 React 生命周期,以便更好地了解何时调用预定义函数。
    猜你喜欢
    • 2020-08-24
    • 2016-10-23
    • 1970-01-01
    • 2015-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-23
    相关资源
    最近更新 更多