HOME>BLOG>
The 10 Commandments in React

The 10 Commandments in React

Ten common coding patterns that are used in React applications

Learning
Web Development
January 8th, 2022 · 8 min read
The 10 Commandments in React

Say you are developing a large or complex application where a well-structured codebase can make it easier to understand how the different pieces of the application fit and grow together, while remaining easy to maintain over time.

Is that even possible in real life? 😱 How? 🧐 Answer: Yes, using coding patterns. (Did I just hear a senior chuckle? 🤨) Knowing the common coding patterns in React and when to use them can help structure the code in a way that is more maintainable, scalable, and reusable.

Here are the Ten Commandments (Coding Patterns) in React every React developer should know (and follow, of course. 😉)

#1 Thou shall separate logical from dumb components

…to promote peace (on your code, at least)

aka Container/presentational pattern: This pattern involves separating the stateful “container” components that handle data and logic from the presentational “dumb” components that are responsible for rendering the UI. This can help to improve the reusability, maintainability, and the world peace of your code.

1// presentational/dumb component
2function UserList(props) {
3 return (
4 <ul>
5 {props.users.map(user => (
6 <li key={user.id}>{user.name}</li>
7 ))}
8 </ul>
9 );
10}
11
12// container/stateful component
13function UserListContainer(props) {
14 const [users, setUsers] = useState([]);
15
16 useEffect(() => {
17 async function fetchUsers() {
18 const response = await fetch('/users');
19 const data = await response.json();
20 setUsers(data);
21 }
22
23 fetchUsers();
24 }, []);
25
26 return <UserList users={users} />;
27}

In this example, the UserList component is a presentational component that is responsible for rendering a list of users. The UserListContainer component is a container component that manages the state and logic for fetching the users data. It uses the useEffect hook to perform an asynchronous fetch request to retrieve the data, and it passes the data down to the UserList component through props.

This separation of concerns can make it easier to maintain and scale the application, as the presentational component is focused solely on rendering the UI, and the container component is responsible for managing the state and logic. The presentational component can be reused in different contexts without having to worry about the state or logic, and the container component can be easily replaced or updated without affecting the UI.


#2 Thou shall know when to summon the higher-order

for commoners err.. common functionalities

aka Higher-order components (HOCs): Higher-order components are functions that take a component as an argument and return a new component with additional functionality. HOCs can be used to add common functionality, such as authentication, data fetching, or error handling, to multiple components.

1import React, { useState, useEffect } from 'react';
2
3// HOC that adds data fetching functionality to a component
4function withData(WrappedComponent) {
5 return function WithData(props) {
6 const [data, setData] = useState(null);
7 const [loading, setLoading] = useState(true);
8 const [error, setError] = useState(null);
9
10 useEffect(() => {
11 async function fetchData() {
12 setLoading(true);
13 try {
14 const response = await fetch('/data');
15 const data = await response.json();
16 setData(data);
17 setLoading(false);
18 } catch (error) {
19 setError(error);
20 setLoading(false);
21 }
22 }
23
24 fetchData();
25 }, []);
26
27 return (
28 <WrappedComponent
29 data={data}
30 loading={loading}
31 error={error}
32 {...props}
33 />
34 );
35 };
36}
37
38// Presentational component that displays data
39function DataList(props) {
40 if (props.loading) {
41 return <p>Loading data...</p>;
42 } else if (props.error) {
43 return <p>Error: {props.error.message}</p>;
44 } else {
45 return (
46 <ul>
47 {props.data.map(item => (
48 <li key={item.id}>{item.name}</li>
49 ))}
50 </ul>
51 );
52 }
53}
54
55// Enhanced component that fetches data
56const DataListWithData = withData(DataList);
57
58function MyComponent() {
59 return <DataListWithData />;
60}

In this example, the withData HOC adds data fetching functionality to the DataList component. The withData HOC uses the useEffect hook to perform an asynchronous fetch request to retrieve the data, and it passes the data, loading state, and error state down to the DataList component through props.

The DataListWithData component is created by calling the withData HOC with the DataList component as an argument. When the DataListWithData component is rendered, it will fetch data from withData which then renders the DataList component with the data populated.


#3 Thou shall share thy blessings

(and thy component’s behavior)

aka Render props: The render props pattern is a technique for sharing behavior between components. It involves exposing a prop that is a function that is called with data and returns a JSX element. This allows the component to be flexible and reusable, as the component’s behavior can be customized by the parent component that uses it.

1import React from 'react';
2
3function DataProvider(props) {
4 const [data, setData] = useState(null);
5
6 useEffect(() => {
7 async function fetchData() {
8 const response = await fetch('/data');
9 const data = await response.json();
10 setData(data);
11 }
12
13 fetchData();
14 }, []);
15
16 return props.render(data);
17}
18
19function MyComponent() {
20 return (
21 <DataProvider render={data => (
22 <div>
23 {data ? (
24 // Render the data here
25 ) : (
26 <p>Loading data...</p>
27 )}
28 </div>
29 )} />
30 );
31}

In this example, the DataProvider component fetches data from the server and exposes it through a render prop. The MyComponent component uses the DataProvider component and provides a function to the render prop that renders the data.

This allows the DataProvider component to be flexible and reusable, as it can be used in any context where data needs to be fetched and rendered. The MyComponent component can customize the behavior of the DataProvider component by providing a different function to the render prop.

Render props are a convenient way to share behavior between components, and they can help to make components more flexible and reusable. They are particularly useful when the behavior of a component needs to be customized based on the context in which it is used.


#4 Thou shall make use of hooks

…it’s a miracle to the React community, really.

Hooks are a way to use state and other React features in functional components. Prior to the introduction of hooks, it was only possible to use state and other React features in class-based components. (cue pails of tears of pre-2019 React devs 😭)

Here’s an example of how to use the useState hook in a functional component in a React application:

1import React, { useState } from 'react';
2
3function Example() {
4 // Declare a state variable called "count"
5 const [count, setCount] = useState(0);
6
7 return (
8 <div>
9 <p>You clicked {count} times</p>
10 <button onClick={() => setCount(count + 1)}>
11 Click me
12 </button>
13 </div>
14 );
15}

In this example, the useState hook is used to declare a state variable called count. The useState hook returns an array with two elements: the current state value, and a function that can be used to update the state value. In this case, the count variable holds the current value of the state, and the setCount function is used to update the value of the state.

The useState hook can be used multiple times in a single component to manage multiple pieces of state.

Here’s an example of how to use the useEffect hook in a functional component in a React application:

1import React, { useState, useEffect } from 'react';
2
3function Example() {
4 const [count, setCount] = useState(0);
5
6 // Similar to componentDidMount and componentDidUpdate
7 useEffect(() => {
8 // Update the document title using the browser API
9 document.title = `You clicked ${count} times`;
10 });
11
12 return (
13 <div>
14 <p>You clicked {count} times</p>
15 <button onClick={() => setCount(count + 1)}>
16 Click me
17 </button>
18 </div>
19 );
20}

In this example, the useEffect hook is used to perform an action after the component has been rendered. The useEffect hook takes a function as an argument, and this function will be called after the component has been rendered. In this case, the function updates the document title using the browser API.

There are many other hooks available in React, and they can be used to perform a variety of tasks such as data fetching, subscribing to events, and managing the lifecycle of a component.


#5 Thou shall only load what shall be loaded

don’t let them users wait for eternity…

aka Lazy loading: Lazy loading is a technique that allows you to defer the loading of a component until it is actually needed. This can be useful in situations where you have a large application with many components, as it can help to improve the performance and loading time of the application by only loading the components that are actually needed.

In React, you can use the React.lazy function and the Suspense component to implement lazy loading. The React.lazy function allows you to import a component that will be loaded asynchronously, and the Suspense component allows you to specify a fallback UI to display while the component is being loaded.

Here’s an example of how to use React.lazy and Suspense to implement lazy loading in a React application:

1import React, { lazy, Suspense } from 'react';
2
3const LazyComponent = lazy(() => import('./LazyComponent'));
4
5function App() {
6 return (
7 <Suspense fallback={<p>Loading...</p>}>
8 <LazyComponent />
9 </Suspense>
10 );
11}

#6 Thou shall split your journey into smaller paths

or the vast ocean that is your codebase into rivers (of joy, I hope)

aka Code splitting: Code splitting is a technique that allows you to split your code into smaller chunks, and only load the code that is needed for a specific route or component. This can help improve the performance of your React application, as it allows you to only load the code that is required for the current view, rather than loading all of the code upfront.

Here is an example of how you can use code splitting in a React application with React Router:

1import React, { Suspense } from 'react';
2import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
3
4const Home = React.lazy(() => import('./routes/Home'));
5const About = React.lazy(() => import('./routes/About'));
6
7function App() {
8 return (
9 <Router>
10 <Suspense fallback={<div>Loading...</div>}>
11 <Switch>
12 <Route exact path="/" component={Home} />
13 <Route path="/about" component={About} />
14 </Switch>
15 </Suspense>
16 </Router>
17 );
18}
19
20export default App;

In this example, the Home and About routes are loaded asynchronously using the React.lazy and Suspense components. This allows the code for these routes to be split into separate bundles, which are only loaded when the route is accessed. The Suspense component is used to provide a fallback element that is displayed while the route is being loaded.

You can also use code splitting with the React.lazy and Suspense components to split code at the component level, rather than at the route level. For example:

1const MyComponent = React.lazy(() => import('./MyComponent'));
2
3function App() {
4 return (
5 <Suspense fallback={<div>Loading...</div>}>
6 <MyComponent />
7 </Suspense>
8 );
9}

In this case, the MyComponent component is loaded asynchronously, and the Suspense component is used to provide a fallback element while the component is being loaded.


#7 Thou shall see the world with patterns

Pattern matching is a technique that allows you to compare a value to a pattern, and execute different code based on whether the value matches the pattern. In React, you can use pattern matching to write more concise and expressive code, particularly when working with props or state that may have multiple possible values.

1function AlertMessages(props) {
2 switch (props.type) {
3 case 'success':
4 return <div style={{ color: 'green' }}>{props.message}</div>;
5 case 'error':
6 return <div style={{ color: 'red' }}>{props.message}</div>;
7 default:
8 return <div>{props.message}</div>;
9 }
10}

In this example, the AlertMessages component takes a type prop and a message prop. The component uses a switch statement to match the type prop against different patterns, and returns a different element based on the value of the type prop.

You can also use the && operator to perform pattern matching in React. For example:

1function AlertMessages(props) {
2 return (
3 <div>
4 {props.type === 'success' && (
5 <div style={{ color: 'green' }}>{props.message}</div>
6 )}
7 {props.type === 'error' && (
8 <div style={{ color: 'red' }}>{props.message}</div>
9 )}
10 {props.type !== 'success' && props.type !== 'error' && (
11 <div>{props.message}</div>
12 )}
13 </div>
14 );
15}

In this example, the AlertMessages component uses the && operator to match the type prop against different patterns, and returns a different element based on the value of the type prop.


#8 Thou shall know your states properly

and manage them accordingly 🕵️‍💁‍

State is an important concept in React, as it allows you to store and manage data that is specific to a particular component. State allows you to create interactive and dynamic components, as the component’s behavior can change in response to changes in state.

There are several different ways to manage state in a React application. One of the most common approaches is to use the useState hook, which is a function provided by React that allows you to add state to functional components.

Here is an example of how you can use the useState hook in a React functional component:

1import { useState } from 'react';
2
3function Counter() {
4 // Declare a state variable and a function to update it
5 const [count, setCount] = useState(0);
6
7 // Increment the count when the button is clicked
8 function handleClick() {
9 setCount(count + 1);
10 }
11
12 return (
13 <div>
14 <p>The count is {count}</p>
15 <button onClick={handleClick}>Increment</button>
16 </div>
17 );
18}

In this example, the Counter component uses the useState hook to declare a state variable called count, which is initialized to 0. It also declares a function called setCount that can be used to update the value of count.

The Counter component renders a button that, when clicked, increments the value of count by calling the setCount function with the new count value. It also displays the current value of count in a paragraph element.

You can also use the useState hook to add multiple state variables to a component. For example:

1import { useState } from 'react';
2
3function User() {
4 // Declare two state variables and two functions to update them
5 const [name, setName] = useState('John');
6 const [age, setAge] = useState(30);
7
8 // Update the name when the input value changes
9 function handleNameChange(event) {
10 setName(event.target.value);
11 }
12
13 // Update the age when the input value changes
14 function handleAgeChange(event) {
15 setAge(event.target.value);
16 }
17
18 return (
19 <div>
20 <p>
21 Name: <input value={name} onChange={handleNameChange} />
22 </p>
23 <p>
24 Age: <input value={age} onChange={handleAgeChange} />
25 </p>
26 </div>
27 );
28}

In this example, the User component uses the useState hook to declare two state variables: name and age. It also declares two functions: setName and setAge, which can be used to update the values of the state variables.

The component renders two input elements that are bound to the name and age state variables, and updates the state variables when the input values change.


#9 Thou shall handle blocking tasks in the background

async I have something to do 🧐, await I remember now 😀💡

Asynchronous programming is a way of writing code that performs tasks that may take some time to complete, such as making network requests or reading from a database. In React, you can use asynchronous programming to handle tasks that need to be performed in the background, without blocking the main thread.

Here is an example of how you can use asynchronous programming in a React component:

1import React, { useState, useEffect } from 'react';
2
3function WaterFetcher() {
4 const [data, setData] = useState(null);
5 const [error, setError] = useState(null);
6 const [loading, setLoading] = useState(false);
7
8 // Fetch data from an API when the component mounts
9 useEffect(() => {
10 async function fetchData() {
11 try {
12 setLoading(true);
13 const response = await fetch('https://wine-api.com/data');
14 const json = await response.json();
15 setData(json);
16 } catch (e) {
17 setError(e);
18 } finally {
19 setLoading(false);
20 }
21 }
22 fetchData();
23 }, []);
24
25 if (loading) {
26 return <div>Loading...</div>;
27 }
28
29 if (error) {
30 return <div>{error.message}</div>;
31 }
32
33 if (data) {
34 return <div>{data.message}</div>;
35 }
36
37 return null;
38}

In this example, the WaterFetcher component uses the useEffect hook to perform an asynchronous task when the component mounts. The task fetches data from an API using the fetch function, and stores the data in the component’s state using the setData function.

The component also has state variables for error and loading, which are used to store any errors that occur during the fetch, and a flag indicating whether the fetch is currently in progress.

The component renders different elements based on the values of these state variables. If loading is true, it displays a loading message. If error is not null, it displays an error message. If data is not null, it displays the data.


#10 Thou shall normalize data

…or suFf3R thE c0n$eQUençeS 😈

Data normalization is the process of transforming data into a consistent and standardized format. Normalizing data can make it easier to work with and analyze, as it can remove any inconsistencies or errors that may be present in the data.

In React, you can use custom functions or helper libraries to normalize data. Here’s an example of using a custom function to normalize data in a React component:

1import React from 'react';
2
3function normalizeData(data) {
4 // Normalize the data here
5 return normalizedData;
6}
7
8function MyComponent(props) {
9 const normalizedData = normalizeData(props.data);
10
11 return (
12 // Render the normalized data here
13 );
14}

Here’s an example of using a helper library to normalize data in a React component:

1import React from 'react';
2import normalize from 'normalize-data-library';
3
4function MyComponent(props) {
5 const normalizedData = normalize(props.data);
6
7 return (
8 // Render the normalized data here
9 );
10}

It’s also possible to use a combination of custom functions and helper libraries to normalize data in a React component.

Keep in mind that the specific steps involved in normalizing data will depend on the format of the data and the desired output.

Data normalization is often an iterative process, as you may need to perform multiple steps in order to fully normalize the data. It’s also a good idea to validate the normalized data to ensure that it is accurate and consistent.


So in summary (or if you scrolled all the way down and didn’t read 😠):

  1. Thou shall separate logical from dumb components: Container/presentational
  2. Thou shall know when to summon the higher-order: Higher-Order Components
  3. Thou shall share thy blessings and thy components behavior: Render Props
  4. Thou shall make use of hooks: Hooks, duh.
  5. Thou shall only load what shall be loaded: Lazy Loading
  6. Thou shall split your journey into smaller paths: Code Splitting
  7. Thou shall see the world with patterns: Pattern Matching
  8. Thou shall know your states properly: State Management
  9. Thou shall handle blocking tasks in the background: Asynchronous Fetching
  10. Thou shall normalize data: Data Normalization

You’ve just seen the surface. There are more advanced patterns you can use for developing apps in React and modern web apps in general. The world is your oyster, lots of pearls out there.

I hope you enjoyed reading and feel free to leave some comments below if you oppose to these commandments or whatnot.

There's more to read!

ArticleInternet of Things, Cybersecurity, Artificial Intelligence, Machine Learning

6 Emerging Trends in the Internet of Things (IoT)

•  8 min read
LearningPersonal Growth

Free Coursera Access with Certifications under the DOST Grant

•  1 min read
Everything Else.
HomeBlogProjects
Works
WebsitesLanding PagesPrintSoftware
Link to $https://github.com/gianfayeLink to $https://www.linkedin.com/gianfaye/Link to $https://twitter.com/gianfayeLink to $https://stackexchange.com/users/2642726/gian-faye?tab=accountsLink to $mailto:contact@gianfaye.com

© 2022 Gian Faye Paguirigan

PrivacyTerms of UseRSS