# React Hooks You Will Love ♥

# Introduction

If there is one this I love, it's doing more, with less. 

`useState` is the bread and butter of React. And it's simplicity offers many use cases. However it's simplicity comes at the cost of having to implement various complexities outside of the hook that could be included in the hook itself.

In this article I offer a few abstractions that you can use and extend to help tackle some of the common use cases you may come across when building an application in React.

# useValue

`useValue` is the simplest in this list. All it adds to `useState` is a utility function that resets the value to whatever you specified as the default value. This however is deceptively useful in situations where you need to clear text boxes and can create a better user experience.

```jsx
const useValue = (defaultValue) => {
	const [value, setValue] = useState(defaultValue);

	const resetValue = () => {
		setValue(defaultValue);
	};

	return [value, setValue, resetValue];
};
```

Here it is in action:

![1.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1660662021055/aCz9Z90q5.gif align="center")

```jsx
const [value, setValue, resetValue] = useValue("Test");

return (
    <>
        <input
		    value={value}
		    onChange={(ev) => setValue(ev.target.value)}
	    />
	    <button onClick={resetValue}>Reset</button>
    </>
);
```

# useCounter

`useCounter` does exactly what it says, it counts. However with a little extra logic around allowing the specification of `min`, `max` and `step` parameters, it becomes everything you need to implement paging, or anything that would require incrementing or decrementing a `number`.

I would use this as a base in a `usePaging` hook for paging logic that fits my specific use case on that page.

```jsx
const useCounter = (defaultValue, step = 1, min, max) => {
	const [value, setValue] = useState(defaultValue);

	const resetValue = () => {
		setValue(defaultValue);
	};

	const setCount = (newValue) => {
		newValue = typeof max === "number" ? Math.min(newValue, max) : value;
		newValue = typeof min === "number" ? Math.max(newValue, min) : value;
		setValue(newValue);
	};

	const increment = () => {
		setValue(
			typeof max === "number" ? Math.min(value + step, max) : value + step
		);
	};

	const decrement = () => {
		setValue(
			typeof min === "number" ? Math.max(value - step, min) : value - step
		);
	};

	return [value, setCount, resetValue, increment, decrement];
};
```

Here it is in action:

![2.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1660662487694/Mxo4CKKoe.gif align="center")

```jsx
const [
	count,
	setCount,
	resetCount,
	incrementCount,
    decrementCount
] = useCounter(1, 5, 0, 400);

return (
    <>  
        <input
		    value={count}
		    onChange={(ev) => setCount(Number(ev.target.value))}
	    />
	    <button onClick={incrementCount}>Increment Count</button>
	    <button onClick={decrementCount}>Decrement Count</button>
	    <button onClick={resetCount}>Reset Count</button>
    </>
);
```

# useObject

`useObject` saves so much boilerplate code over time and can be used in some really sophisticated use cases elegantly. The main use case for it is simply filling out a form of many values that you eventually need to validate and send off to an API. I use this constantly and it has saved me so many keystrokes!

```jsx
const useObject = (defaultObj) => {
	const [obj, setObj] = useState(defaultObj);

	const updateObj = (updateObj) => {
		setObj({ ...obj, ...updateObj });
	};

	const resetObj = () => {
		setObj(defaultObj);
	};

	return [obj, setObj, updateObj, resetObj];
};
```

Here it is in action:

![3.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1660663257318/ww0lSYACC.gif align="center")

```jsx
const [
	person,
	/* setPerson not needed */,
	updatePerson,
	resetPerson
] = useObject({});

return (
    <>  
        <input
			value={person.name || ""}
			onChange={(ev) => updatePerson({ name: ev.target.value })}
		/>
		<input
			value={person.country || ""}
			onChange={(ev) => updatePerson({ country: ev.target.value })}
		/>
		<button onClick={resetPerson}>Reset</button>
		<p>{JSON.stringify(person, null, 2)}</p>
    </>
);
```

# useArray

`useArray` is another one that blew me away when I first used it! You can extend this hook to expose any array operations you like and never have to do another shallow clone in you component to get the changes to reflect ever again! Need a map function? Throw it in there!

```jsx
const useArray = (defaultArray) => {
	const [arr, setArr] = useState(defaultArray);

	const push = (value) => {
		setArr([...arr, value]);
	};

	const unshift = (value) => {
		setArr([value, ...arr]);
	};

	const pop = () => {
		const current = [...arr];
		const deleted = current.pop();
		setArr(current);
		return deleted;
	};

	const shift = () => {
		const current = [...arr];
		const deleted = current.shift();
		setArr(current);
		return deleted;
	};

	const concat = (newArr) => {
		setArr([...arr, ...newArr]);
	};

	const inverseConcat = (newArr) => {
		setArr([...newArr, ...arr]);
	};

	const splice = (index) => {
		const current = [...arr];
		current.splice(index, 1);
		setArr(current);
	};

	const reset = () => {
		setArr(defaultArray);
	};

	return [
		arr,
		setArr,
		{
			push,
			unshift,
			pop,
			shift,
			concat,
			inverseConcat,
			splice,
			reset
		}
	];
};
```

Here it is in action:

> Note the use of `useValue` for the `input` allowing me to easily clear it when `push` or `Unshift` are clicked 😉

![4.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1660664000876/-uZhI9M8T.gif align="center")

```jsx
const [
	people,
	/* setPeople not needed */,
	{
		push: pushPeople,
		unshift: unshiftPeople,
		pop: popPeople,
		shift: shiftPeople,
		reset: resetPeople,
		splice: splicePeople
	}
] = useArray([]);

return (
    <>  
        <div>
		    <input
				value={name}
				placeholder="Name"
				onChange={(ev) => setName(ev.target.value)}
			/>
			<button
				onClick={() => {
					pushPeople(name);
					resetName();
				}}
			>
				Push
			</button>
			<button
				onClick={() => {
					unshiftPeople(name);
					resetName();
				}}
			>
				Unshift
			</button>
			<button onClick={() => popPeople()}>Pop</button>
			<button onClick={() => shiftPeople()}>Shift</button>
			<button onClick={() => resetPeople()}>Reset</button>
		</div>
		<ol>
			{people.map((p, i) => (
				<li key={i}>
					{p}{" "}
					<button onClick={() => splicePeople(i)}>
						Delete
					</button>
				</li>
			))}
		</ol>
    </>
);

```

# Conclusion

That's it! I hope this article helps you reduce the code you need to write, and gets you thinking about how you can use custom hooks for elegant abstractions 👍

Follow me on [Twitter](https://twitter.com/SamDarylDev) to keep up to date with my projects and get notified of new articles like this in the future!
