Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gladiatorAsh/bdcc81772a5e1c9c8804eb45e8cf9439 to your computer and use it in GitHub Desktop.
Save gladiatorAsh/bdcc81772a5e1c9c8804eb45e8cf9439 to your computer and use it in GitHub Desktop.
React "controlled" vs "uncontrolled" inputs explanation

[12:03 AM] acemarke: "controlled" and "uncontrolled" inputs
[12:04 AM] acemarke: if I have a plain, normal HTML page, and I put <input id="myTextbox" type="text" /> in my page(edited)
[12:04 AM] acemarke: and I start typing into that textbox
[12:04 AM] acemarke: it remembers what I've typed. The browser stores the current value for that input
[12:05 AM] acemarke: and then sometime later, I can get the actual element, say, const input = document.getElementById("myTextbox"), and I can ask it for its value: const currentText = input.value;
[12:05 AM] acemarke: good so far?
[12:08 AM] acemarke: I'll keep going, and let me know if you have questions
[12:08 AM] lozio: ok, actually I'm reading
[12:09 AM] lozio: good
[12:09 AM] acemarke: so, a normal HTML input field effectively stores its own value at all times, and you can get the element and ask for its value
[12:09 AM] acemarke: this is what we refer to as an "uncontrolled" input
[12:09 AM] acemarke: and is what you're probably used to with, say, jQuery or Backbone or similar
[12:10 AM] acemarke: I write my HTML form, I have a Submit button, when the button is clicked, I get each input and grab the value, put all the values in an object, and do something with that
[12:10 AM] acemarke: but, in React, the normal way we do things is different
[12:10 AM] acemarke: with React, normally every time we render we define what the current DOM output should be
[12:10 AM] acemarke: and indeed, in React, you can still create "uncontrolled" inputs:
[12:11 AM] lozio: use 'ref' right?
[12:11 AM] acemarke: yep, like:
[12:12 AM] acemarke:

const MyComponent extends Component {  
    onClick() {  
        const input = this.refs.myInput;  
        const value = input.value;  
        // do something with the value  
    }  
  
    render() {  
        return <input type="text" ref="myInput" />  
    }  
}  

[12:12 AM] acemarke: roughly
[12:13 AM] acemarke: but, there's a more React-standard way to do things
[12:13 AM] acemarke: with React, we can render an input, and tell it what its value should be: return <input type="text" value="Hello world!" />
[12:13 AM] acemarke: (this applies to all input types, btw, not just type="text")
[12:14 AM] acemarke: but, now we have a problem
[12:14 AM] acemarke: if I put my cursor in that input after the '!', and try to type "asdf".... nothing will happen
[12:14 AM] acemarke: because every time I type, React will re-render
[12:14 AM] acemarke: and React will see that the value is supposed to be "Hello world!"
[12:15 AM] lozio: Yes, That's my problem so far
[12:15 AM] acemarke: and when I type that first 'a' and the value becomes "Hello world!a", React will overwrite it
[12:15 AM] lozio: You explained my problem very well
[12:16 AM] acemarke: So, a "controlled" input is when you specify the value. And, in order to update the value, you must also specify an onChange callback for the input. The event in the callback will have the new suggested value from the input. It is then your job to take that new value and put it somewhere in your state, then re-render with the new value
[12:17 AM] acemarke:

class MyComponent extends Component {  
    constructor(props) {  
        super(props);  
          
        this.state = {  
            text : ""  
        };  
          
        this.onChange = this.onChange.bind(this);  
    }  
      
    onChange(e) {  
        const newText = e.target.value;  
        this.setState({text : newText});  
    }  
      
    render() {  
        return <input type="text" value={this.state.text} onChange={this.onChange} />  
    }  
}  

[12:18 AM] acemarke: so every time I type another character into that textbox, it fires "onChange", I take the new value, put it in the component's state, and re-render with the new value
[12:19 AM] acemarke: it may sound a bit more complicated. but, that means you never have trouble with your inputs being out of sync with your data
[12:19 AM] acemarke: because you always have the values in your state
[12:19 AM] acemarke: does that make sense?
[12:22 AM] lozio: What if I use Redux's store state value inject an input value, because Redux's state is not a React Component state
[12:23 AM] acemarke: same thing. doesn't matter whether you're putting the new value into Redux or React component state. It's the use of <input value={someValue} onChange={someOnChange} /> that makes it "controlled"
[12:24 AM] acemarke: that said, you might not want to go straight to Redux for every single character typed
[12:24 AM] acemarke: that could be a lot of actions
[12:24 AM] acemarke: and the data from Redux is coming back down to a React component anyway

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment