React - change input defaultValue by passing props
Solution 1
As a previous answer mentioned, defaultValue
only gets set on initial load for a form. After that, it won't get "naturally" updated because the intent was only to set an initial default value.
You can get around this if you need to by passing a key
to the wrapper component, like on your Field
or App
component, though in more practical circumstances, it would probably be a form
component. A good key
would be a unique value for the resource being passed to the form - like the id stored in the database, for example.
In your simplified case, you could do this in your Field render:
<div key={this.props.value}>
<input type="text" defaultValue={this.props.value || ''} />
</div>
In a more complex form case, something like this might get what you want if for example, your onSubmit action submitted to an API but stayed on the same page:
const Form = ({item, onSubmit}) => {
return (
<form onSubmit={onSubmit} key={item.id}>
<label>
First Name
<input type="text" name="firstName" defaultValue={item.firstName} />
</label>
<label>
Last Name
<input type="text" name="lastName" defaultValue={item.lastName} />
</label>
<button>Submit!</button>
</form>
)
}
Form.defaultProps = {
item: {}
}
Form.propTypes = {
item: PropTypes.object,
onSubmit: PropTypes.func.isRequired
}
When using uncontrolled form inputs, we generally don't care about the values until after they are submitted, so that's why it's more ideal to only force a re-render when you really want to update the defaultValues (after submit, not on every change of the individual input).
If you're also editing the same form and fear the API response could come back with different values, you could provide a combined key of something like id plus timestamp.
Solution 2
defaultValue only works for the initial load. After that, it won't get updated. You need to maintain the state for you Field component:
var Field = React.createClass({
//transfer props to state on load
getInitialState: function () {
return {value: this.props.value};
},
//if the parent component updates the prop, force re-render
componentWillReceiveProps: function(nextProps) {
this.setState({value: nextProps.value});
},
//re-render when input changes
_handleChange: function (e){
this.setState({value: e.target.value});
},
render: function () {
// render based on state
return (
<div>
<input type="text" onChange={this._handleChange}
value={this.state.value || ''} />
</div>
);
}
});
Solution 3
I'm fairly certain this has to do with Controlled vs. Uncontrolled inputs.
If I understand correctly, since your <input>
is Uncontrolled (doesn't define a value
attribute), then the value will always resolve to the value that it is initialized with. In this case Hello!
.
In order to overcome this issue, you can add a value
attribute and set it during the onChange
:
var Field = React.createClass({
render: function () {
// never renders new value...
return (
<div>
<input type="text" defaultValue={this.props.default || ''} value={this.props.value} />
</div>
);
}
});
Here is a plunker showing the change.
Solution 4
You can make the input conditionally and then every time you want to force an update of the defaultValue
you just need to unmount the input and then immediately render it again.
![Kosmetika](https://i.stack.imgur.com/8iBJ9.jpg?s=256&g=1)
Comments
-
Kosmetika almost 2 years
Consider this example:
var Field = React.createClass({ render: function () { // never renders new value... return ( <div> <input type="text" defaultValue={this.props.value || ''} /> </div> ); } }); var App = React.createClass({ getInitialState: function () { return {value: 'Hello!'}; }, changeTo: function (str) { this.setState({value: str}); }, render: function () { return ( <div> <Field value={this.state.value} /> <button onClick={this.changeTo.bind(null, 'Whyyyy?')}>Change to "Whyyyy?"</button> <button onClick={this.changeTo.bind(null, void 0)}>Change to undefined</button> </div> ); } }); React.render( <App />, document.getElementById('app') );
I want to pass value into
defaultValue
as prop of dumb input component. However it never re-renders it. -
JohnnyQ almost 8 yearsIs this the cleanest way to resolve uncontrolled inputs? Also I don't see any
onChange
function on your example. -
David over 7 yearsThis breaks the React philosophy I think
-
Davin Tryon over 7 years@JohnnyQ uncontrolled components don't need an
onChange
. Usually, the value is extracted using aref
. -
Arthur Kushman over 7 yearsSplendid, there is a bug with value setting and other keys like onKeyUp/onKeyPress, so if U need, by some circumstances, the onKeyUp event for ex, you should set onChange on the same function, otherwise the value attribute won't be updated.
-
Meysam Feghhi almost 7 yearsthis should be the best answer
-
azriebakri almost 6 yearsYou're a life saver <3
-
gsziszi over 5 yearsUsing the value as a key is just a hack, it mounts the element as many times as the value changes. Although it could solve your problem it is not the best way to update your input value. Actually it does not update the value but creates a new one (it can lead to memory leaks in extreme cases). It is better to use a controlled input field instead of this solution.
-
Yehuda Kremer over 4 yearsBTW for multiple values you can use: key={[props.values.a, props.values.b]}
-
Harshad Prajapati over 4 yearsYou save my day!
-
Harshad Prajapati over 4 yearsThis should be the best answer
-
bikram about 4 years@Sia key={this.props.value} is the solution. Do you think that it has any performance impact?
-
siva surya over 3 yearsFelt lucky to see this fix sooner :)