Refs is more than enough
M. Akbar Nugroho
Posted on February 20, 2023
This story started when I learning React.js for the first time. Where I see a lot of influencers overused the React.useState
or generally speaking, a React.js state.
Let's be honest, we ever put a React state on every HTML input we have. When it has two inputs, no problem occur.
Sometime, your PM tells you to add a new feature and guest what? You add more and more state. Leading your application slow because of unnecessary re-render.
And now, you confuse why the application so slow even crashed on older browser.
...or maybe, Refs is the answer you looking for?
State: The Sweat Part
No doubt. React state helps us when dealing with interactive UI. For example you have a filter feature. You can filter your data by date, category, etc and display the filtered data.
Normally, your code looks like this.
const Filter = () => {
const [filter, setFilter] = useState(null);
const fetchDataWithFilter = (e) => {
setFilter(e.target.value);
/** Fetching data... */
};
return (
<div>
<p>Filter by: {filter || 'none'}</p>
<select onChange={fetchDataWithFilter(filter)}>
<option value="monthly">Monthly<option>
<option value="cluster">Cluster</option>
</select>
{/** data display goes here... */}
</div>
);
}
As the result, you have beautiful and interactive filter feature.
At this point, theres no thing wrong with this approach. But, what happens when you have a case like managing values inside a form?.
State: The Sour Part
When you have a case like product entry form, normally you have >= 5 input fields. If you use React state for each input field to listen for value changes it's not good because your form will re-renders many times.
Let's imagine your client types 5 (average) letters for each input field and the form should have 5 (key hits) * 5 (input fields) = 25 (re-renders).
const ProductEntry = () => {
/** States declarations... */
return (
<form>
<input name="name" onKeyUp={e => setName(e.target.value)} />
<input name="price" onKeyUp={e => setPrice(e.target.value)} />
<input name="stocks" onKeyUp={e => setStocks(e.target.value)} />
{/** Rest of input fields... */}
</form>
);
};
The benefit is you always got uptodate values where you can validate the values on the fly. But, you will have performance worst.
Refs: The Healthy Sweat
Instead of putting states for each input fields, you can use ref for getting the values without causing re-renders.
const ProductEntry = () => {
/** Refs declarations... */
return (
<form>
<input name="name" ref={inputNameRef} />
<input name="price" ref={inputPriceRef} />
<input name="stocks" ref={inputStocksRef} />
{/** Rest of input fields... */}
</form>
);
};
With this approach, no matter how much your client types in the input fields, React shouldn't re-renders the form.
The downside is you need to add extra step for process the values (validate, sanitize, etc).
We can use a pattern called observer to handle the downside. Instead of process the values on the fly, we process it when some event fired. Normally when the form is being submitted.
const ProductEntry = () => {
/** Refs declarations... */
const submit = () => {
// 1. Collect all values
// 2. Validate
// 3. Sanitize
// 4. Perform HTTP request
};
return (
<form>
<input name="name" ref={inputNameRef} />
<input name="price" ref={inputPriceRef} />
<input name="stocks" ref={inputStocksRef} />
{/** Rest of input fields... */}
<button onClick={submit}>Save Product</button>
</form>
);
};
So, before the button is clicked, no actions is running and less of re-renders.
Objectives
Use state wisely
State makes our app interactive and it's awesome. When dealing with large app, you should pay attention of every state change.
Too many re-renders is not good for you app. Except you isolate it, so others parts not affected.
Use refs with observer pattern
It sounds every technical, but actually it's very simple concept. Just run your functions when an event fired.
-
Button clicked -> run submit() function
. -
Dropdown changed -> run fetchDataWithFilter() function
.
Inside those functions, you can access your refs and process it as usual.
Use form validation library
Don't so diligent. You shouldn't to manually validate your form. Use a correct library instead. One of my recommendation is react-hook-form.
It implement refs and observer pattern. So don't be worry of unnecessary re-renders. And also I have wrote a guide how to use it :).
๐ Thanks for reading!
Posted on February 20, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 28, 2024
November 27, 2024