Design Patterns🎨💚

Bhagya
SLIIT Women In FOSS Community
4 min readJul 28, 2022

A “pattern” in programming refers to a broad, reusable solution to a frequently occurring issue. Knowing when to employ these patterns is crucial for software developers since the indiscriminate application of these patterns might have a negative impact on the quality of your software.

I finished reading “Learning Patterns” by Lydia Hallie and Addy Osmani over the weekend. Any level of the developer can learn about different design patterns, when to employ them, and their benefits and drawbacks from this book. Techniques for improving web performance are also included.

1. Singleton

A single global instance known as a singleton is available across the whole application. This technique enables managing states and gaining global access to them simple in React projects.

Singletons should be avoided because they are seen as an anti-pattern in JavaScript. We may immediately build an object in JavaScript to implement a similar pattern without really establishing a Singleton class, unlike Java, C++, or C#.

These are a few drawbacks of this pattern:

  1. The existence of global variables may lead to overwrites and unexpected behavior.
  2. It is challenging to test because we cannot create a new instance; instead, we must test the value based on any changes made by earlier tests.
  3. .Since Redux and other state management tools are already present in React apps, the Singleton paradigm is largely unnecessary.

2. Provider

The Provider pattern is commonly seen in React. Passing props from one component to another is just very tedious as the app gets more complex. This is known as prop drilling.

One example React has implemented to overcome this challenge is the React Context API. It allows data to be accessible from any component in the component tree.

For example, you may need to check whether a user is logged in throughout your app. So you need to wrap all your elements inside some kind of AuthProvider so that any components in this Provider can access its prop.

We first create a Context object like this:

export const AuthContext = React.createContext();

Then, we can have a Provider with a prop we want to be accessible everywhere in our app. Here we have a user state that the AuthProvider will provide to the rest of the components.

export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);

useEffect(() => {
app.auth().onAuthStateChanged(setUser);
}, []);

return (
<AuthContext.Provider value={{ user }}>{children}</AuthContext.Provider>
);

Now we just need to wrap it around all our elements.

function App() {
return (
<AuthProvider>
<Router>
<Nav />
<Switch>
<Route path="/signin" component={SignIn} />
</Switch>
</div>
</Router>
</AuthProvider>
);
}

And now our app components can access user anywhere like this:

const { user } = useContext(AuthContext);

3. Hooks

Hooks in React has become one of the most powerful features to write cleaner and more efficient code. It is not exactly a design pattern, but ever since its release, it has replaced many traditional patterns. According to the official React website, Hooks achieves the following:

  • Allow you to reuse stateful logic without changing your component hierarchy
  • Let you split one component into smaller functions based on what pieces are related (such as setting up a subscription or fetching data)
  • Let you use more of React’s features without classes

Before Hooks, the only way to handle state and lifecycle methods in React was through class components. As the program expanded, it became more difficult to restructure functional components to class components or to have numerous duplicate lifecycle functions.

4. Container

The Container pattern is next on the list. If you are unfamiliar with React, you may have missed this pattern. The goal of applying this pattern is to divide the functional components that deal with application logic from the display components of the app (just UI).

There are two categories of components:

  1. Presentational component — simply about displaying data to user
  2. Container component — cares about what data is shown to user

For example, the logic for fetching data from an API will be in a Container component while the Presentational component will get the data to display it in a readable format.

This pattern is advantageous as it enforces the separation of concerns. It makes it easy for developers to test and to make changes to the view or the logic whenever needed.

5. Factory

As its name suggests, the factory pattern is about using factory functions to create objects over and over again, without the new keyword.

Take a look at the example below:

// Factory function
const createShape = ({numberOfSides, color}) =>({
numberOfSides,
color
})
// create objects from factory
const square = createShape({
numberOfSides: 4,
color: "red"
})
const hexagon = createShape({
numberOfSides: 6,
color: "yellow"
})

When you need to design intricate, customizable objects that share certain attributes, this pattern can be helpful. The drawback is that creating new instances rather than objects in JavaScript could use less memory.

Because patterns are tried-and-true answers to frequent problems in software design, knowing some patterns will help you as a developer with problem-solving and software design concepts.

--

--