Functional Programming Techniques

As a language, JavaScript is conducive to functional programming. The notes below cover some of the more common functional programming techniques in JavaScript.

Hooking

⚠️ This section assumes familiary with the React library.

Hooking is a functional programming pattern for handling side-effects. In a broad sense, hooks are simply wrappers for generic callback functions. To understand why hooks exist, consider the following React component:

export const Greet = ({ greeting }) => {
	return <div>{greeting}</div>;
};

to use this component, we simply write:

<Greet greeting="Hello" />

This is React's approach to creating web applications. The entire application is some state, and to change how the application looks or behaves, we modify its state. Hooks are patterns for performing these modifications.

UseState

Suppose we had the following component:

export const Counter = () => {
	let counter = 0;
	return <div>{counter}</div>;
};

Now we want a button with the following action: If we click the button, the value increments. So, we modify our component by including a button. We then assign an incrementing function to the button's onClick attribute:

export const Counter = () => {
	let counter = 0;
	const increment = () => {
		counter = counter + 1;
	};
	return (
		<div>
			{counter}
			<button onClick={increment}>++</button>
		</div>
	);
};

If we click on the button above, nothing happens. The counter variable, however, is in fact changing. So why aren't we seeing the value change? Because React doesn't know that the application's state has changed. The counter variable changed, but that variable is not actually hooked onto the application's state. And because it isn't hooked on to the application's state, React isn't prompted to re-render the component.

To hook the counter variable on to the state, we can use the useState() hook.

import { useState } from "react";

export const Counter = () => {
	const [counter, setCounter] = useState(0); // the initial value

	const increment = () => {
		setCounter(counter + 1);
	};

	return (
		<div>
			{counter}
			<button onClick={increment}>++</button>
		</div>
	);
};

The useState() hook consists of a few parts to get all of this working. Let's take a closer look at the syntax:

The useState() hook can be thought of as encapsulating the following declaration:

Where v is some value with the initial value i, f is a function that updates the value of v at the time f is called.

UseReducer

Suppose we had the following component:

import { useState } from "react";

export const Parity = () => {
	const [counter, setCounter] = useState(0);
	const [parity, changeParity] = useState(true);
	const clickHandler = () => {
		setCounter(counter + 1);
		changeParity(!parity);
	};
	return (
		<>
			<div>{counter}</div>
			<button onClick={clickHandler}>++</button>
			<div>{parity ? "even" : "odd"}</div>
		</>
	);
};

In the component above, we have a click-handler that modifies two states — one that increments the value, and the other that changes the text from even to odd. For this sample component, the code above is fine. However, we can imagine a component with numerous states. And the more states we have, the more unwieldy our click-handler can get.

This is where the useReduce() hook comes in handy:

import { useReducer } from "react";

export const Parity = () => {
	const reducer = (state, action) => {
		switch (action.type) {
			case "increment":
				return { counter: state.counter + 1, parity: state.parity };
			case "changeParity":
				return { counter: state.counter, parity: !state.parity };
			default:
				return state;
		}
	};
	const [state, dispatch] = useReducer(reducer, {
		counter: 0,
		parity: true,
	});
	const clickHandler = () => {
		dispatch({ type: "increment" });
		dispatch({ type: "changeParity" });
	};
	return (
		<>
			<div>{state.counter}</div>
			<button onClick={clickHandler}>++</button>
			<div>{state.parity ? "even" : "odd"}</div>
		</>
	);
};

The useReducer() hook has similar syntax to useState(). The difference, however, is that it gives us a better handle on state changes. The syntax:

In the syntax above, obj{obj} (the state object) is an object containing the states we want to mutate in our component. This object is bound to the identifier s{s} (the state identifier). To modify the state object, we use the reducer function r.{r.} This is a function with the following syntax:

Above, s{s} is the state identifier we used earlier. This is what gives the reducer function access to the previous state. The second parameter is an action object. This object essentially allows the reducer function to run through the list of states, comparing this object against each list entry (in our example, this is done with a switch statement). If it encounters a matching entry, it performs that entry's associated procedure.

To actually execute the reducer function, we call the dispatch function d.{d.} The dispatch function has the syntax d(a),{d(a),} where a{a} is the action object earlier-mentioned.

UseEffect

Arguably, the most powerful and oft-used hook is UseEffect().