Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set defaultValue, value={this.props.value}, and update the value of a text input with React?

Summary:

I'm attempting to make a blog with React and seem to have hit a snag in setting and updating a text field. I have the blog text and user name from a database and want to set the blog text in a text window for a given user. Then when the user types I also want to update that text.

Attempt:

If I set my textarea value={this.props.name} it will correctly set the value but won't update. If I set it to update with {this.state.value} then it starts off blank but will update correctly. I can find examples of how either set the default value or update the value. I can't figure out how to do both. Thank you in advance.

ClickScreen React Component Call within App

<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}
/>

BlogEntry React Component Call within ClickScreen Page:

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

EditBlog React Component

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

Update: There were some issues in my understanding between the distinction of a controlled and uncontrolled React component and the React lifecycle. Now the value is set in getInitialState and then updated appropriately in componentWillReceiveProps. Thank you everyone!

Changes:

  • componentDidMount -> componentWillReceiveProps. This has to do with the React component lifecycle.
  • The text area defaultValue={this.props.name} has been changed to reflect the updated state value of value={this.state.value}.
  • this.state.value=this.props.value in the render function has been removed.
       // 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>
            );
          }
        });
like image 216
SaundersB Avatar asked May 15 '16 18:05

SaundersB


People also ask

How do you get the input type text value in React?

To get the value of an input field in React:Use event. target. value to get the input field's value and update the state variable.

Can props update value in React?

A component cannot update its own props unless they are arrays or objects (having a component update its own props even if possible is an anti-pattern), but can update its state and the props of its children.

How do you set a default value to props?

The defaultProps is a React component property that allows you to set default values for the props argument. If the prop property is passed, it will be changed. The defaultProps can be defined as a property on the component class itself, to set the default props for the class.


3 Answers

so, whenever you want to edit props, you have to set them in the local component state ( like you did in the getInitialState by setting value to the props ). Props are immutable, so setting the value or defaultValue of the input to the prop will/should not allow you to change the prop.

So below, what I have done is set value of the input to this.state.name, and this.state.name is set to this.props.name on initial state and whenever you call update, it will update the components state with whatever is typed in the input.

if you need to pass the name back to a parent component, then you need to pass in a function from the parent which you can then call from the child to inform the parent that the name value has changed, parent will then need to update the name which then gets passed back down to the child...this creates a 2 way data binding..

// 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>
    );
  }
});
like image 86
fayzaan Avatar answered Oct 30 '22 08:10

fayzaan


For forms in React:

The defaultValue and defaultChecked props are only used during initial render. If you need to update the value in a subsequent render, you will need to use a controlled component.

Docs on controlled components

like image 26
omarjmh Avatar answered Oct 30 '22 07:10

omarjmh


Reading your code, there is no need to:

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

The job is already done by getInitialState. If you intend to have the state updated when the component receive new props you should write:

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

I think that, in your case, you should use this.state.value and that it is not well initialized because componentWillReceiveProps was no implemented to update the component state when receiving a props.name value different from undefined.

like image 43
Damien Leroux Avatar answered Oct 30 '22 09:10

Damien Leroux