DISCLAIMER: i'm new at React, and just trying to build good habits.
So, the example would be a simple contacts app, where you type in names, and all the names are rendered below the input field. pic.1 simple contacts app mechanics
First, and the most intuitive way, of making this work is using useState()
hook with our input field. It's also widely suggested in tutorials around the web.
method 1 with useState()
:
const [inputState, setInputState] = useState('');
const [people, setPeople] = useState([]);
const onChange = (event) => {
setInputState(event.target.value)
}
const onSubmit = (e) => {
e.preventDefault()
setPeople([...people, inputState])
setInputState('') // pay extra attention to this line
}
// ...
<form onSubmit={onSubmit}>
<input onChange={onChange} value={inputState} />
</form>
//...
Looks simple enough. We have inputState
, that is up-to-date with input field because of onChange
function. However (!!!), in this video about common react-hook mistakes, Kyle points, that this method isn't the optimal one, cause it makes the whole page re-render every time we change input value. So, he suggests using useRef()
hook instead.
*method 2 with useRef()
:*
const [people, setPeople] = useState([]);
const inputRef = useRef([]);
const onSubmit = (e) => {
e.preventDefault()
setPeople([...people, inputRef.current.value])
// inputRef.current.value = '' <== won't work
}
// ...
<form onSubmit={onSubmit}>
<input ref={inputRef} />
</form>
//...
The second method works fine, and re-renders the page only once, when the submit event happens. However, we are going to submit this form multiple times, so we want onSubmit
function to clear the input value. If we try adding inputRef.current.value = '';
in the end of onSubmit
function, it breaks our app. The reason must be that setting state is asynchronous, so it ends up with updating state after making input value empty. To resolve it we can use another hook, useEffect()
, which will clear our input value only after our stateful element is updated
method 2 updated with useEffect()
:
const [people, setPeople] = useState([]);
const inputRef = useRef([]);
useEffect(() => inputRef.current.value = '', [people])
const onSubmit = (e) => {
e.preventDefault()
setPeople([...people, inputRef.current.value])
}
// ...
<form onSubmit={onSubmit}>
<input ref={inputRef} />
</form>
//...
Finally. What's the question??
We have these two methods:
First one is intuitive, using simple mechanics, using just one hook, BUT re-rendering the page multiple times.
Second one uses as much as three different hooks, more complex mechanics, BUT re-renders only on submit.
Which should I use? Which could be considered the correct one? Or maybe I'm missing something and the answer is 'neither'?
Some similar questions here discuss the differences, but as we are already aware of differences, what to choose?
If your form doesn't have validation, you can use
useRef
.
But should I? Does this stack of hooks really improve the performance?
I haven't watched the video, but if the author suggests to use useRef()
instead of state to save performance, he doesn't seem to have much clue of how React actually works.
React only applies changes to the DOM when it spots the changes in the virtual DOM, which is the representation of the nodes used to keep track of necessary changes. If your state change causes many DOM updates, it means that you do it wrong, most likely recreate a state value unnecessarily. The easiest way to this mistake is to recreate object in state, instead of memoizing it.
Using states means achieving much cleaner and reusable React code. Use useRef()
only when you need to perform an action on a DOM element (like focus()
) or when you need a value that needs to be accessed in the same cycle and/or is not rendered.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With