Often, it can be useful to know what the user’s input is as they’re typing it and use that information to change what is rendered. This can be good for dynamic search or filter inputs, or triggering changes when a user checks a checkbox, or a myriad of other use cases. In this example, we’re going to dynamically show an error message if the user types something invalid so they don’t have to wait until they submit the form to know they’re doing something wrong.
To do this we’ll store the input’s value in state and then use that state to derive an error message which will be displayed if there is an error.
Kent C. Dodds: [0:00] Let's say that this UsenameForm cannot have UPPER case characters. They can only have lower case characters. We could show the user an error when they hit the Submit button, but it would be a lot better user experience if we display an error message as they're making changes to this input field if they change it to something that's not allowed.
[0:18] We need to know what the user's typing as they're typing it, not just as they submit it, so we're going to add an onChange handler right here and here we'll call this handleChange. We'll make a function handleChange(), and that will take the event. Then we can use event.target.
[0:36] Because the target of this handleChange(event) is our input, then event.target is going to be the input, .value is going to be the username. We need to store that username somewhere and trigger re-render of the UsenameForm so that it displays the error message if the username is typed incorrectly.
[0:55] Let's go ahead and add some state to this UsenameForm. We'll say [username, setUsername] = React.useState('') and we'll initialize that to an empty string. In here, we'll call setUsername with the event.target.value, and then we no longer need to get the username from the form input elements because we're always going to be keeping this username up-to-date with whatever the user's specifying.
[1:21] We can get rid of that, and now this username is just referencing that.
[1:25] Next, let's go ahead and determine whether this isLowerCase by saying username === username.toLowerCase(). If it's equal to its toLowerCase version of itself, then we know that it is lower case, and we know that we have an error if it's not lower case. If it is lower case, we'll just say the error is null, otherwise we'll say the Username must be lower case.
[1:52] Then we just need to display that error message. We'll copy that, come down here and make a <div> here with a style = { color: 'red' } just for the fun of it. We'll put the error message right in there.
[2:05] We can also make the button disabled if there's an error. Disabled accepts a Boolean, so we'll just say Boolean_error. If error is truthy, then we'll pass a true value for disabled, and if there is no error or it's falsy, then we'll pass a false value for disabled.
[2:25] Let's save that. We get a refresh. If we type an upper-case character, then we'll get Username must be lower case, the Submit button is disabled. If we type a lower-case character, then we don't get any problem, until we get an upper-case character in there.
[2:40] If you ever need to know exactly what the user's typing as they're typing it, then you can use the onChange event to get access to the value of the input and update that in the state of your component, then changes to that value will trigger a re-render of your component. That state value will be whatever the user's typed, allowing us to create this error message based on whether the username is lower case.
[3:03] We display that error message here in red in this <div>. We disable the submit button if there is an error message.