useState vs useRef: Tussle of Titans

Search for a command to run...

No comments yet. Be the first to comment.
š” āSo if you want to go fast, if you want to get done quickly, if you want your code to be easy to write, make it easy to read.ā -By Robert C. Martin JavaScript has progressed a ton in recent years. If you are learning JavaScript in 2022 and you ...

Before beginning our quest to find how not to use Create React App. First, letās see why we need Create React App in the first place. Why do we need Create React App? š¤ Create React App is a comfortable environment for learning React and is the best...

Getting Started with Node.js In this blog, we will try to understand the basics of Node.js, how it works, and why to choose Node.js, but before diving into node let's talk a little bit about Java-script. JavaScript is one of the best programming lang...

If you are reading this, you probably know what React.js is and might have already used it Earlier. However, you might be wondering why I am reading about folder structure? Canāt I just stuff all my files in the src folder?? 𤪠Technically you could ...

Letās first understand š¤ What is an Array? Quoting from MDN directly. The Array object, as with arrays in other programming languages, enables storing a collection of multiple items under a single variable name and has members for performing common...

Hooks let developers use state and other React features without writing a class. Hooks were introduced in React 16.8 to facilitate programmers in the reusability of React code.
They are the functions that "hook into" React state and lifecycle features from function components. It does not work inside classes.
If writing a function component and realizing the need to add some state to it, previously we had to convert it to a class. Now we can use a Hook inside the existing function component.
useState hook is the primary building block that enables functional components to hold state between re-renders. It enables the development of the component state for functional components.
import React, { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<button onClick={() => setCount(count + 1)}>Count is :{count}</button>
</div>
);
}
Above is the code for functional implementation of React useState and below is the equivalent CodeSandbox Output .
https://codesandbox.io/embed/priceless-fast-hijeoo?fontsize=14&hidenavigation=1&theme=dark
Letās see the same code using class components-based method.
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
We see how much the code is reduced significantly and using functional components and hook also makes code much clearer by not using this keyword and eliminating a wrapper constructor within class component.
First of all, it declares āstate variablesā. It is used to preserve value between the function calls. Normally, common Javascript variables like ( let, var, const) disappear after the function call. However, state variables preserve the values.
[count,setCount]=useState(0)
count is the state variable that will be used to represent the value assigned using the hook.setCount is a functional variable whose sole purpose is updating count state variable.useState initial argument is passed which is used for the initial value of the count after initial rendering.useState it returns an array with two items. The first one is the current value and the second is a function that updates it.React will remember its current value between re-renders, and provide the most recent one to our function. If we want to update the current
count, we can callsetCountWhen the App component re-renders, its children would re-render.
const [localState, setLocalState] = useState(props.theme);
The useRef Hook allows persisting values between renders. It can be used to store a mutable value that does not cause a re-render when updated. It can be used to access a DOM element directly.
It does everything that useState does but without re-rendering the components.
useRefreturns a mutable ref object whose .currentproperty is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
useRef should be used.import { useState, useRef } from "react";
import "./styles.css";
export default function AppDemo11() {
const [value, setValue] = useState("");
const valueRef = useRef();
console.log("render");
const handleClick = () => {
console.log(valueRef);
setValue(valueRef.current.value);
};
return (
<div className="App">
<h4>Value: {value}</h4>
<input ref={valueRef} />
<button onClick={handleClick}>click</button>
</div>
);
}
We see the code used for useRef and equivalent output in CodeSandbox.
https://codesandbox.io/embed/cranky-ellis-1s6jrt?fontsize=14&hidenavigation=1&theme=dark
We see that component only renders after button click function rather than rendering on each keystroke.
When we āsubmitā the input with a button to update the state variable value.With the refproperty, React provides direct access to React components or HTML elements.
<input ref={valueRef} />
If this had been done using useState and onChange which each keystroke input the component would have re-rendered. With each keystroke, component is re-rendered.
We see that in effect in the below code and itās output in CodeSandBox.
import { useState, useRef, useEffect } from "react";
import "./styles.css";
export default function AppDemo11() {
const [value, setValue] = useState("");
const rendercount = useRef(0);
useEffect(() => {
rendercount.current = rendercount.current + 1;
console.log(rendercount.current);
});
const handleChange = (e) => {
setValue(e.target.value);
};
return (
<div className="App">
<input value={value} onChange={handleChange} />
<h4>Renders:{rendercount.current} </h4>
</div>
);
}
(https://codesandbox.io/embed/competent-cerf-6e3vp0?fontsize=14&hidenavigation=1&theme=dark)
However, using useRef makes sure that the component is rendered only once after the button is clicked.
const valueRef = useRef(null);
const onButtonClick = () => {
console.log(valueRef.current.value);
};
valueRef is the variable that stores the value to be persisted.useRef statement, it is provided the initial value which should be assigned to useRef on the first render.valueRef using .current keyword. This is because useRef is like a box that holds its mutable value in its .current property.Keep in mind that
useRefdoesnātnotify when its content changes. Mutating the.currentproperty doesnāt cause a re-render.
We have already seen two major use cases for useRef over useState
useRef and useState.useState code:
import { useState, useRef, useEffect } from "react";
import "./styles.css";
export default function AppDemo11() {
const [value, setValue] = useState("");
const [rendercount,setrenderCount] = useState(0);
useEffect(() => {
setrenderCount(rendercount+ 1);
});
const handleChange = (e) => {
setValue(e.target.value);
};
return (
<div className="App">
<input value={value} onChange={handleChange} />
<h4>Renders:{renderco} </h4>
</div>
);
}
This above code will cause infinite renders as every time rendercount value is updated the entire component is re-rendered.
useRef code:
Equivalent use case can be achieved using useRef whererin within useEffect hook ( important to use within useEffect to avoid side effects) rendercount.current value is updated which doesnāt trigger any re rendering.
import { useState, useRef, useEffect } from "react";
import "./styles.css";
export default function AppDemo11() {
const [value, setValue] = useState("");
const rendercount = useRef(0);
useEffect(() => {
rendercount.current = rendercount.current + 1;
console.log(rendercount.current);
});
const handleChange = (e) => {
setValue(e.target.value);
};
return (
<div className="App">
<input value={value} onChange={handleChange} />
<h4>Renders:{rendercount.current} </h4>
</div>
);
}
useState and useRef .The code is for printing āA second has passedā in console for each passing second
useState code:
We see in this code that it goes into an infinite loop and keeps on re-rendering.
As with each update of state variable intervalUse component is re-rendered. Code goes into infinite loop hell.
import "./styles.css";
import React, { useRef, useEffect, useState } from "react";
export default function App() {
const [intervalUse,setintevalUse]= useState()
useEffect(() => {
const id = setInterval(() => {
console.log("A second has passed");
}, 1000);
setintevalUse(id)
});
return (
<div>
</div>
);
}
useRef code:
So to prevent inifinte loop hell we use useRef.
With each passing second āA second has passedā is printed on the console and state variable val is updated which is rendered on the screen.
import "./styles.css";
import React, { useRef, useEffect, useState } from "react";
export default function App() {
const[val,setVal]=useState(0)
const intervalRef = useRef();
useEffect(() => {
const id = setInterval(() => {
setVal(val+1)
console.log("A second has passed");
}, 1000);
intervalRef.current = id;
return () => clearInterval(intervalRef.current);
});
const handleCancel = () => clearInterval(intervalRef.current);
return (
<div>
<div>Value is {val}</div>
</div>
);
}
See the ouput in CodeSandBox. Using useRef makes sure that there is no case for inifinite rendering.
https://codesandbox.io/embed/upbeat-ganguly-nbg47c?fontsize=14&hidenavigation=1&theme=dark
useState Hook with its updater function causes re-renders.useRef returns an object with a current property holding the actual value. In contrast, useState returns an array with two elements: the first item constitutes the state, and the second item represents the state updater functioncurrent property in useRef is mutable however useState state variable is not. We need updater function to update useState state variable.useState and useRef both are Hooks, but only useRef can be used to gain direct access to React components or DOM elements.It should be clear by now that useState is to be used if we want to update data and cause a UI update.
And useRef is to be used if data is to be persisted throughout the lifecycle without re-renders.