This is the third post in the series.
React.js has been successfully added to out Asp.Net MVC web app in part 1. I created a React driven user listing and maintenance page on part 2.
In this post, I will create a Custom Hook to remove the need to use the same piece of code in each React web page.
Copy Paste Programming, DRY and Technical Debt
As more and more pages are added to the project, I found that certain blocks of code are repeated in each. This is especially true of the data-binding code, which is a copy-and-paste action onto every new page that needs to use controlled components for data entry and modification.
Copy Paste Programming violates the DRY Principle (Don’t Repeat Yourself) and should be considered for refactoring taking into account the Techical Debt introduced with each repitition of the code.
Let’s add a new product listing and editing page to our web app, which will be very similar to our user pages.
And a snippet of the React javascript that wires up the Product component:
|
|
Notice the handleInputChange and handleCheckBoxChange functions, that are exact copies of the same functions in the user controlled component. There is also some duplication in the handleSubmit function, preventing the default submit action and performing an Ajax call. I will need this functionality on each web page that contains a controlled component.
As the React documentation explains so simply:
So let’s pay off some technical debt, and refactor this common code into a custom hook.
A Custom Hook for React data-binding
My first refactoring will look at DRYing up the input change event handlers
//reactFormBinding.js
'use strict';
export const reactFormBinding = (state, callBack) => {
const [values, setValues] = React.useState(state);
const handleInputChange = (e) => {
setValues(prev => ({ ...prev, [e.target.name]: e.target.value }));
};
const handleCheckBoxChange = (e) => {
setValues(prev => ({ ...prev, [e.target.name]: e.target.checked }));
};
return {
handleInputChange,
handleCheckBoxChange,
values,
};
};
The destructuring code changes from
'use strict';
let products;
......
function Product(props) {
const [values, setValues] = React.useState(props.product);
to:
'use strict';
import { reactFormBinding } from "./reactFormBinding.js";
let products;
......
function Product(props) {
const { values, handleInputChange, handleCheckBoxChange } = reactFormBinding(props.product);
Notice that handleInputChange and handleCheckBoxChange only differ on the e.target property that is used to assign the value to state. The second refactoring consolidates the two event handlers into one, the target element type check determining whcih property to use:
const handleInputChange = (e) => {
setValues(inputs => {
return { ...inputs, [e.target.name]: e.target.type === 'checkbox' ? e.target.checked : e.target.value };
})
};
return {
handleInputChange,
values,
};
Regards,
Paul.