Make Dynamic Forms with React

InstructorKent C. Dodds

Share this video with your friends

Send Tweet

Static forms don't give the user a lot of information about how to submit the form. We can use Reacts onChange prop on an input to dynamically update the form; disabling and enabling the submit button on a condition. This allows for custom validation as the user makes changes to the input.

Girma Nigusse
~ 7 years ago

after we add <button disabled={Boolean(error)} type="submit">Submit</button>, the alert(error: ${error}) statement inside handleSubmit will never execute. And can be removed.

Arden de
~ 7 years ago

after we add <button disabled={Boolean(error)} type="submit">Submit</button>, the alert(error: ${error}) statement inside handleSubmit will never execute. And can be removed.

Agreed. I think this could be slightly confusing to people and might best be removed after adding the boolean

Konekoya
~ 7 years ago

Hi Kent,

Why you return null from getErrorMessage() if the given param doesn't match any of above if statements? And why you use disabled=Boolean(error) instead of disabled={error}

Thanks :)

Kent C. Doddsinstructor
~ 7 years ago

Hi Konekoya! I prefer explicitness. It helps future code readers know my intentions. If I didn't return anything, then it could be interpreted that the original coder hadn't considered that case. I also like to be explicit about my booleans, so rather than relying on truthiness/falsiness, I generally cast things to booleans with the Boolean constructor.

I hope that's helpful.

Bijoy Thomas
~ 7 years ago

Thoughts on returning an empty div element when there is no error?

error ? <div style={{color: 'red'}}>{error}</div> : <div/>

That way the Submit button doesn't jump up.

Kent C. Doddsinstructor
~ 7 years ago

Bijoy, that'd be fine. You could also accomplish that with styling. But it really doesn't matter either way.

Brendan Whiting
~ 6 years ago

Isn't it bad UX to yell at people for having invalid input before they've even had a chance to type something? In the angular world, there's these values for a 'dirty' or 'pristine' form that we can use, is there a React equivalent?

Kent C. Doddsinstructor
~ 6 years ago

You're correct Brendan, I would probably want to do more work here for a better user experience. React doesn't have support for things like dirty or pristine. You'll have to implement that yourself. You might consider using formik or react-final-form.

Brendan Whiting
~ 6 years ago

Okay cool. I guess this is one of those things where React is more of an 'ecosystem' of 3rd party libraries, for better or worse, and Angular is more of an opinionated framework.

Greg Fisher
~ 6 years ago
<NameForm 
    getErrorMessage= {value => {
      if (value.length < 3) {
        ...

Where does the value come from here?

Kent C. Doddsinstructor
~ 6 years ago

@Greg, That's provided by the caller (see references to this.props.getErrorMessage).

Greg Fisher
~ 6 years ago

Ah, now I see it. Thank you!

Veekas Shrivastava
~ 6 years ago

Hi Kent, why did you make getErrorMessage a prop instead of a method inside <NameForm />? Personal preference or is there an advantage to initializing this way?

Kent C. Doddsinstructor
~ 6 years ago

It was just a way I could show the functionality without including the implementation details in the NameForm.

Sawyer McLane
~ 6 years ago

Is there any advantage in using

        {error ? (
          <div style={{color: 'red'}}>
            {error}
          </div>
        ) : null}

over

        {error && (
          <div style={{color: 'red'}}>
            {error}
          </div>
        )}
Kent C. Doddsinstructor
~ 6 years ago

As I said on twitter recently:

I make it a rule to prefer ternaries over &&

I've been burned by react rendering 0 instead of not rendering something because I did:

{users.length && users.map(/* stuff */)}

So I just avoid the problem altogether by using ternaries.

Sawyer McLane
~ 6 years ago

I've been burned by react rendering 0 instead of not rendering something because I did:

{users.length && users.map(/* stuff */)}

Why would this render 0? Is that a bug? Or is there something about map() that I don't understand?

Kent C. Doddsinstructor
~ 6 years ago

Try this in your console:

var users = []
console.log(users.length && users.map(() => {}))

You'll get the output is 0

In React, doing the above is effectively doing this:

<div>{0}</div>

It will render 0. This is because 0 is a falsey value so the right side of the && is not evaluated and the left side (0) is used for the expression value.

jdukelee
~ 6 years ago

Hey Kent, When we initialize the components state and call getErrorMessage() with an empty string, the length of value is 0 and the first if condition (value.length < 3) seems to be met resulting in an error message being displayed on first render. I see one way this could be handled is to add another condition to getErrorMessage() i.e. length === 0 or some other 'initializing condition' and return an empty string. Understanding that this example is for learning purposes and a production form may have a very different implementation I'm just interested to hear your thoughts on this and any other approaches you may have to handle this scenario...Thanks much.

Kent C. Doddsinstructor
~ 6 years ago

Yup, the use cases vary and you have the flexibility of JavaScript to create the user experience that you need :)

Anil Jeeyani
~ 6 years ago

I am seeing setState method being used from last couple of lessons. is that the this.setState comes with React.Component? so you have to use class to use this method, any other implementation to use this method? any other methods like this that we should be knowing and useful?

Kent C. Doddsinstructor
~ 6 years ago

There are other things available, but you don't typically use anything other than setState(), props, and state

Tahsin Yazkan
~ 5 years ago