7
votes

I went through the docs of react, about controlled and uncontrolled components. I have created a simple use case where I want to enforce the user to enter only uppercase values in the input field.

In the first case I have used 'ref' with 'onChange' to achieve this and a global object's property to capture the dom node.Here's the code for that - https://jsfiddle.net/69z2wepo/78064/

class Nikhil extends React.Component {
   constructor(props){
      super(props);
        this.field = {
            input: ''
        };
      }
    foo() {
       this.y = this.field.input;
       this.y.value = this.y.value.toUpperCase();
     }
    render() {
      return (
        <div>
           <input ref={ node => this.field.input = node } onChange={ this.foo.bind(this) }/>
        </div>
       );
     }
   }

ReactDOM.render(<Nikhil/>,container);

In the second case I have used 'value' property and state with'onChange'. Here's the code for that -https://jsfiddle.net/69z2wepo/78066/

class Nikhil extends React.Component {
  constructor(props){
    super(props);
    this.state = {
        input: ''
    };
  }
  foo(e) {
    this.setState({ input: e.target.value.toUpperCase() });
  } 
  render() {
    return (
      <div>
        <input value= { this.state.input } onChange={ this.foo.bind(this) }/>
      </div>
    );
  }
}

ReactDOM.render(<Nikhil/>,container);

The docs says:

 With a controlled component, every state mutation will have an 
 associated handler function. This makes it straightforward to 
 modify or validate user input. For example, if we wanted to enforce 
 that names are written with all uppercase letters, we could write 
 handleChange as:

 handleChange(event) {
  this.setState({ value: event.target.value.toUpperCase()} );
 }

Well I can validate the user input even when I am not using state, and not syncing the value prop with state , as done in the first example above.

  1. So definitely validating user input can be done without using state at all ?

  2. Can you explain why one approach is better than the other ?

  3. What exactly the 'single source of truth' means and why it is so important ?

In both the cases I am using a global variable of the component which is an object and can be accessed throughout the component.

  1. Also why should I unnecessarily use value = { this.state.input } in example 2, because that would call render on every keystroke, whereas in case 1 render is called only once. So isn't performance in case 1 better than 2 ?

Also from the docs:

 To write an uncontrolled component, instead of writing an 
 event handler for every state update, you can use a ref to get 
 form values from the DOM

Well I need to write an event handler like 'onChange' even when using 'ref' to validate user input at run time as done in case 1. So using event handler with 'ref' is normal ?

Use case for state variable -- From my understanding the only case where I have no other option than to use state variable is when I need to update the view dynamically. Because this.setState() calls render every time it is run . Here's the code for that -https://jsfiddle.net/69z2wepo/78068/

class Nikhil extends React.Component {
  constructor(props){
  super(props);
    this.state = {
        input: ''
    };
  }
  foo(e) {
    this.setState({ input: e.target.value });
  }
  render() {
    return (
    <div>
      <input onChange={ this.foo.bind(this) }/>
        <p>{ this.state.input }</p>
    </div>
  );
 }
}

ReactDOM.render(<Nikhil/>,container);

I will be grateful if someone could clarify on all the three examples and enhance my understanding of the above concepts.

2
try not having state. just render an input with no onchange. thats what an uncontrolled input is. let the dom element handle inputs. then when you go to use the value inside it. use a ref to access the value of the input.John Ruddell
on the other hand, if you want a predictable UI use controlled components and never have to worry if you remembered to update the node ref or notthedude

2 Answers

4
votes

According to React Docs - https://facebook.github.io/react/docs/refs-and-the-dom.html:

Don't Overuse Refs

Your first inclination may be to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy

In rare cases, you might want to have access to a child's DOM node from a parent component. This is generally not recommended because it breaks component encapsulation, but it can occasionally be useful for triggering focus or measuring the size or position of a child DOM node.

I think the general idea is that, if you are using React, you should use what react does better, that is the state manipulation using setState.

2
votes
  1. Use ref method to create a new item of a collection via submit. Let's assume you have a MongoDB collection called cars. If you want to add a car via form submission you should use the ref method.

  2. Use value (onChange) method to edit an existing item: Let's assume you want to change the price of your car collection for certain car. You mirror the state with the input, so by typing, you also change the state at the same time.

React's official docs do recommend the second method, but you cannot change a value of an item that doesn't exist, so in these cases the first method is the appropriate one.