15

I have the following code in my component. It will get called when I update certain things, thereby replacing a bunch of things in the UI. Everything is updating EXCEPT the value of the input as seen by the user.

let input = {
  id: 'discount-' + geo + '-' + segment,
  value: percentage,
  disabled: applyToAll,
  placeholder: '0.00'
};

cells.push(
  <td key={'cell-' + geo + '-' + segment} className="discount-segment cfix">
    <Text {...input} />
  </td>
);

This is what <Text> returns, with things removed for clarity

return (
  <div className={containerClasses.join(' ')} id={'field-container-' + id}>
    {label}
    <input
      autoComplete="off"
      type="text"
      id={id}
      ref="input"
      {...extraProps}
      name={id}
      className={classes.join(' ')}
      defaultValue={this.props.value}
      onChange={this.props.onChange}
      />
  </div>
);

Everything renders fine. Let's say the percentage value is 5 on start, it will show 5 in the field. I then do something else that updates percentage to 50. (A console log will show the right number on re-render). However the value is only showing 5 in the UI still. I am using defaultValue on the input field, but I figure that should be changing as the whole thing re-renders from parent.

Edit Updated <Text> to set value instead of defaultValue. However then I need to use state to update the value when user types. Then when I re-render, I'm sending in new props with proper value, but of course props isn't updated. Catch-22 for me.

9
  • Are you sure the whole thing re-renders? What happens when you try to use value instead of defaultValue? (Plus, what's this.props.onChange doing?) Commented Apr 18, 2016 at 0:45
  • @TAGraves Right now I am not passing in onChange.. so nothing there. The lines above that show me using <Text> are inside render of a component. The render method has {cells} inside and that is getting called every time I expect it to be. Commented Apr 18, 2016 at 1:18
  • That doesn't mean that your input is being unmounted and then a new input is being rendered, though. defaultValue can't be updated after an initial render. Commented Apr 18, 2016 at 12:12
  • @TAGraces interesting, I'll have to give it a shot shortly. I remember ( a while back ) when I was using just value, it would go into read-only mode for certain inputs. Commented Apr 18, 2016 at 14:20
  • Yes, using value will make it a controlled input, so you'll have to update the value of the input in your onChange handler. Commented Apr 18, 2016 at 14:22

4 Answers 4

30

You need to perform a couple of steps:

  1. Your input needs to only use the value and onChange props, do not use defaultValue
  2. Initialize your state using your props to set your default value
  3. Update your state when your props change

So, for example:

const MyComponent = React.createClass({

  propTypes: {
    defaultInputValue: React.PropTypes.string
  },

  getInitialState() {
    return {
      inputValue: this.props.defaultInputValue
    };
  },

  componentWillReceiveProps(nextProps) {
    if (nextProps.defaultInputValue !== this.props.inputValue) {
      //Forcibly overwrite input value to new default if the default ever changes
      this.setState({inputValue: nextProps.defaultInputValue});
    }
  },

  render() {
    return <input type="text"
                  value={this.state.inputValue}
                  onChange={e => this.setState({inputValue: e.target.value})} />;
  }
});

In general initializing state off of props is a no-no. I would probably cringe a little bit if I saw this come across in a code review as there is probably some behavior that can be simplified.

You can also do:

<input value={this.state.inputValue || this.props.defaultInputValue} />

Such that the value of the input reverts to the prop value if you ever clear out the input. In this case you wouldn't have to forcibly overwrite the state with the new props.

Sign up to request clarification or add additional context in comments.

1 Comment

Ahhh componentWillReceiveProps is a method I had glanced earlier and it didn't click. Thanks!
2

componentWillReceiveProps is deprecated now, and even its successor getDerivedStateFromProps is recommended against. To square the circle of "I need to manage the state of a text input (state), but I also need it to update its initial value when I re-render (props)", the React blog recommended using a key in the props. When the key changes, the component remounts and props can initialize state anew.

To aggressively force the component to refresh whenever anything about the input changes, I would use

    <Text {...input} key={JSON.stringify(input)}/>

Then you can use value={this.state.value} like a normal controlled form, but you can set this.state.value = props.value and it will change every time.

Comments

2

We can do it as this.We Must have to use onChnage() Event.

<input placeholder="as_you_want"
       value={this.state.as_your_state}
       onChange={e => {
           this.setState({ as_your_state: e.target.value });
           this.value = this.state.as_your_state;
       }}
/>

Hope This Works.

1 Comment

This is also the solution if you are wanting to use multiple select input boxes that are dependant on each other. Thanks @Usama
0

In my case, I just wanted to have the change handler not directly attached to the input but to the element wrapping it. It wasn't working because the input was using value instead of checked for the attribute...

Issue

<div onClick={() => setCheckboxVal(!checkboxVal)}>
  <input
    type="checkbox"
    name="a-checkbox"
    value={checkboxVal}
  />
  <label htmlFor="a-checkbox"> Click Me</label>
</div>

Solution

<div onClick={() => setCheckboxVal(!checkboxVal)}>
  <input
    type="checkbox"
    name="a-checkbox"
    checked={checkboxVal}
    readOnly
  />
  <label htmlFor="a-checkbox"> Click Me</label>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.