DEV Community

Simplify controlled components with React hooks

Stanley Jovel on August 13, 2019

While working with react it is almost inevitable to come across controlled components. A controlled component is a react component that controls th...
Collapse
 
dmikester1 profile image
Mike Dodge • • Edited

Wow! This is the cleanest and easiest I have seen a controlled input done. I have one question. Every other time I've looked up a tutorial on how to do a controlled input, they have always set the input value to the state variable, e.g.

<input type='text' value='startDate' onchange='changeDate' />

How does this work without requiring the value atribute?

Collapse
 
stanleyjovel profile image
Stanley Jovel •

Hello Mike! It should work with or without explicitly setting the value attribute.
Try it yourself by running the source code on repl.it :
repl.it/@StanleyJovel/Controlled-C...

However, the example code you shared doesn't seem to be valid JSX.

Collapse
 
dmikester1 profile image
Mike Dodge •

Oh, you mean the missing curly braces? Yeah, I forgot to type those, but they are in my code. What I'm stuck on is how to change those input values from another component? I have lifted the state to a shared parent. But when I add in value={batchDates.startDate} to my input, I get: Warning: A component is changing an uncontrolled input of type date to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

Thread Thread
 
stanleyjovel profile image
Stanley Jovel •

Interesting, Is it okay if I take a look at some of your code?

Thread Thread
 
dmikester1 profile image
Mike Dodge •

OK, nevermind, figured it out! :) I wasn't initializing my state variables correctly. But I think in order to be able to set it from a different component, I will need to have that value attribute set to a state value.

Thread Thread
 
stanleyjovel profile image
Stanley Jovel •

Awesome 😃

Collapse
 
evanlk profile image
Evan Kennedy • • Edited

I'd also like to point out that you could also add additional functionality such as 'setDefaults', or 'clearValues' too.

import { useState } from 'react'

export const useInputChange = (defaultValues) => {
  const [input, setInput] = useState({...defaultValues})

  const handleInputChange = (e) => setInput({
    ...input,
    [e.currentTarget.name]: e.currentTarget.value
  })

  const setDefaults = () => {
     setInput({...defaultValues});
  }

  const clearValues = () => {
    setInput({});
  }

  return [input, handleInputChange, clearValues, setDefaults]
}
Collapse
 
chandra profile image
Chandra Prakash Tiwari •

This is a good approach, but this didn't worked for me.
still showing

index.js:1 Warning: A component is changing an uncontrolled input of type number to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://fb.me/react-controlled-components
Collapse
 
chandra profile image
Chandra Prakash Tiwari •

I think you are not using the value of the state object as the value of input..
this is not the controlled input here.

<input type="text" name="username" onChange={handleInputChange} />
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ianhancock36 profile image
IanHancock36 •

Just got out of a bootcamp was struggling with handle changes and hooks etc this makes so much sense and I really like how the hooks is in a separate file which allows a such a clean reading ability thank you for this article!!!

Collapse
 
dmikester1 profile image
Mike Dodge •

Stanley, wow small world!! I just saw you graduated in Computer Science from UW-Eau Claire. I graduated in Computer Science from UW-Eau Claire as well!!

Collapse
 
stanleyjovel profile image
Stanley Jovel •

Really?! That is so awesome!
I did not graduate there though haha I did a 1-year exchange program and absolutely loved it.

Collapse
 
nikolalakovic85 profile image
Nikola Lakovic •

Perfect Stanley! :) Thanks!

Collapse
 
meefox profile image
Ju •

"THIS APPROACH IS NOT SCALABLE"
unless this.setState({[event.target.name]: event.target.value})
;)

Collapse
 
stanleyjovel profile image
Stanley Jovel •

Yes, that is why I'm using that exact approach