Why Functional Programming

James Slaughter Development Technologies, JavaScript, React Leave a Comment

Every React Dev Should Get Familiar With Functional Programming.

React has gotten a little funny of late – a few years ago, it was normal to embrace the Object-Oriented paradigm, writing each component as a class and doing lots of this-binding.

Today, however, hooks and functional components have taken over React, and with it, a style of programming unusual for front-end frameworks is growing in popularity: Functional Programming.

This programming style has been in use for many years: Lisp, Haskell, Clojure, and OCaml are all established, though mainly out of the mainstream, languages with a rich history and broad application. Thinking ‘functions are first-class citizens’ sounds strange, especially to new JavaScript developers who have spent most of their time in Python or Java that come from an Object-Oriented perspective.

That’s why in this post, we will go over the basics of Functional Programming: function composition and how we can combine functions easily, and then we’ll take those broadly applicable patterns to modern React through Higher-Order Components.

This article assumes a basic knowledge of Javascript web apps implemented with React, but if you’d like to master this front-end development framework before diving into Functional Programming, here is a great resource to do so!

Functional Programming Goals and Lingo

There is a lot of Deep Nerdery associated with functional programming: Category Theory, Functors, and worse: these things called Monads. While academic-sounding lingo can make some eyes cross, the patterns behind these things can be pretty powerful and help us write more maintainable code, and that is always fun!

I don’t think that there’s a lot of reason to delve deeper into very mathy topics; instead, we will keep focused on using functional programming to write better React code.

Functional programming aims to encapsulate as little scope as possible in each function (the principle of Do One Thing Well). Thus, if we need complex behavior from our programming, then we can compose simple functions together.

Here’s a simple example of function composition, we do this all the time:

const suffixWithWorld = (someText) => someText + " World";
const prefixWithHello = (otherText) => "Hello " + otherText;

// we can call them together:
console.log(suffixWithWorld(prefixWithHello("Interrupted"))); // Hello Interrupted World

// or we can make a new function:
const wrapHelloWorld = (middleText) =>
  suffixWithWorld(prefixWithHello(middleText));

console.log(wrapHelloWorld("Middle")); // Hello Middle World

To be sure, suffixWithWorld(prefixWithHello("Interrupted")) looks hard to read. You can imagine it getting out of hand if you’re trying to compose several functions, each with verbose, well-chosen names.

Also, English reads left-to-right, but the functions are executed right to left (‘Hello’ is added before ‘World’). In functional programming, we often use a helper function called pipe that can help us stick functions together:

const pipe =
  (...fns) =>
  (inputVal) =>
    fns.reduce(
      (outputFromPrevious, nextFunction) => nextFunction(outputFromPrevious),
      inputVal
    );

Let’s break this down:

(...fns) gathers the arguments of functions into an array called fns. That array is then reduced by calling each function in the array, starting with an initial input value.

You might ask, “Yeah, but what’s with the second arrow? Am I making two functions?”

This is a function that returns a function as a value. This is now ‘Functional Programming.

You did it! We are returning a function that takes a single value and runs it through each of the given functions in order, with the output of one function as the input of the next function. Returning to our wrapper example, we can see how we might use this:

// first call suffixWithWorld, and pass its output to prefixWithHello.
const wrapHelloWorld = pipe(suffixWithWorld, prefixWithHello);
console.log(wrapHelloWorld("Piped")); // Hello Piped World

If we make many small utility functions, we can then pipe them together into a single function.

What If My Function Has Multiple Parameters?

You might have heard of currying. This is not cooking delicious spicy food. In Functional Programming, we refer to currying as the process of breaking a function out into multiple single-parameter functions.

const logFormatter = (prefix, message) => `${prefix} ::: ${message}`;

// currying can help make this more useful for composition,
// since it has a single-value signature.
const makeLogFormatter = (prefix) => (message) => `${prefix} ::: ${message}`;
const fooLogger = makeLogFormatter("In Foo");

fooLogger("Starting..."); // returns "In foo ::: Starting..."

Currying can provide a closure for the prefix as well (this is called Partial Application), or, you can slightly modify the function to return whatever value it’s ultimately passed so that our logger can be inserted anywhere in the pipeline:

const logFormatter = (logHow) => (prefix) => (message) => (value) => {
  logHow(`${prefix} ::: ${message}`);
  return value;
};

// can be reused for other loggers too
const consoleLogger = logFormatter(console.log);
// then set the prefix wee want
const fooConsoleLogger = consoleLogger("In foo");

const fooLogPipeline = pipe(
  fooConsoleLogger("-----BEGIN-----"),
  getSomeStuff,
  fooConsoleLogger("Got Stuff!"),
  doThingsToStuff,
  fooConsoleLogger("Things done!"),
  cleanStuffUp,
  fooConsoleLogger("Cleaned!"),
  fooConsoleLogger("------END------")
);

Now you can pass a value through a pipeline and get logged steps in between, and not have to worry about cluttering up your code for getSomeStuff with logging statements.

Exercise for the reader: How can we use closures to make this logger display the number of milliseconds between each step?

Ok, But React Though

Consider that React Functional Components are single-parameter/curried, with the props argument containing everything we need to build our component. One way that functional programming has leaked into React is through the use of Higher-Order Components (HOCs).

Suppose you have a specific behavior and you want several components to share this behavior. For example, maybe we have a new logging API, and we want to post to it whenever certain components are rendered, but we don’t, and we won’t always know which components we’d like to log. We can do this when the component comes alive with a useEffect hook, of course.

const logMyComponent = (ComponentToLog) => (props) => {
  useEffect(() =>
    axios.post(`ultraLogger.fake/log`, { message: new Date().toString()}),
    []
  );
  return <ComponentToLog {...props} />;
};

const Footer = (props) => (
  <div className="footStyle">{props.children} © 2021</div>
);

const FooterWithLogging = logMyComponent(Footer);

/// later on ... ///
<FooterWithLogging>This Footer is monitored</FooterWithLogging>;

FooterWithLogging will now post that request every time it’s loaded, and we didn’t have to touch the Footer component at all.

Side note: The useEffect function’s name comes from Functional Programming lingo. A function that returns identical output for the same input is called a ‘Pure Function.’ Functions that do ‘things’ beyond returning a value are said to have ‘Side Effects,’ and that is what useEffect does – it encapsulates things that are to be done besides rendering a React Component.

Perhaps more practically, if we had several effects that we wanted to apply to many different components, we can compose them together:

const superConnectify = pipe(
  getAuthToken,
  subscribeToSubscriptions,
  withReduxProvider
);

Suppose you want a component that gets an auth token, subscribes to something vital, and exists inside a Redux Provider. In that case, you can write each of those functions completely separately, compose them together with pipe, then pass whatever React component (perhaps you have several Page components) you’d like to superConnectify. This allows you to separate your concerns more effectively, avoid repeating yourself, and let your functions and React components Do One Thing Well.

This Is Only the Tip of the Iceberg!

Higher-Order Components are all well and good, but the React-savvy reader should be thinking to themselves, “can’t I do the same thing with custom hooks?” The answer is, of course you can! Moreover, those hooks can be just as composable. Finally, since hook signatures are up to the developer, they too can be curried and piped about. Let’s take a deeper look next time!

Today, we learned about the general approach of Functional Programming: how we compose functions, a handy implementation of a ‘pipe’ function that will compose functions, the process of currying and functions-as-return-value, and how we can use these concepts in React using Higher-Order Components.

Check back soon for more installments!

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments