DEV Community

Cover image for SOLID in React Native - part 1
Davi Silva
Davi Silva

Posted on

2

SOLID in React Native - part 1

The SOLID acronym refers to five rules in software design. Based on these rules we can create software that is better understood, more flexible, and easier to maintain. In this post, we will introduce the first of these principles - the Single Responsability Principle, applied to mobile development with React Native, but equally applicable to any React application.

Single Responsibility Principle (SRP) - "A class ought to serve a single, clearly defined purpose, reducing the need for frequent changes."

Let's take a look at the ListRepos component below and analyze what it's doing:

import React, { useEffect, useState } from 'react';
import { View, Text, Alert, ActivityIndicator } from 'react-native';

import axios from 'axios';

type Repo = {
  id: string;
  language: string;
  name: string;
};

export const ListRepos = () => {
  const [repos, setRepos] = useState<Array<Repo>>([]);
  const [isLoading, setIsLoading] = useState<boolean>(true);

  useEffect(() => {
    (async () => {
      try {
        const { data } = await axios.get(
          'https://api.github.com/users/davi1985/repos'
        );

        setRepos(data);
      } catch (error) {
        Alert.alert('Something wrong!');
      } finally {
        setIsLoading(false);
      }
    })();
  }, []);

  if (isLoading) {
    return <ActivityIndicator size={'large'} color={'#4285F4'} />;
  }

  return (
    <View>
      {repos.map((item) => (
        <View key={item.id}>
          <Text>{item.name}</Text>
          <Text>{item.language}</Text>
        </View>
      ))}
    </View>
  );
};
Enter fullscreen mode Exit fullscreen mode

We can observe that the component is:

  • performing data fetching
  • rendering the list of repositories, and
  • managing states

Thinking about SOLID, specifically the Single Responsibility Principle (SRP), we can separate responsibilities. First of all, let's isolate the data fetching part into a hook:

import { useState, useEffect } from 'react';
import { Alert } from 'react-native';

import axios from 'axios';

type Repo = {
  id: string;
  language: string;
  name: string;
};

export const useGetRepos = () => {
  const [repos, setRepos] = useState<Array<Repo>>([]);
  const [isLoading, setIsLoading] = useState<boolean>(true);

  useEffect(() => {
    (async () => {
      try {
        const { data } = await axios.get(
          'https://api.github.com/users/davi1985/repos'
        );

        setRepos(data);
      } catch (error) {
        Alert.alert('Something wrong!');
      } finally {
        setIsLoading(false);
      }
    })();
  }, []);

  return { isLoading, repos };
};
Enter fullscreen mode Exit fullscreen mode

Now, our ListRepos component is cleaner and has fewer responsibilities: take a look:

import React from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
import { useGetRepos } from './useGetRepos';

export const ListRepos = () => {
  const { isLoading, repos } = useGetRepos();

  if (isLoading) {
    return <ActivityIndicator size={'large'} color={'#4285F4'} />;
  }

  return (
    <View>
      {repos.map((item) => (
        <View key={item.id}>
          <Text>{item.name}</Text>
          <Text>{item.language}</Text>
        </View>
      ))}
    </View>
  );
};
Enter fullscreen mode Exit fullscreen mode

We can make it even better. If we observe, each item in our list is being rendered directly in our main component. We can separate it and pass what is necessary for its rendering via props. Take a look:

import { Text, View } from 'react-native';

type Props = {
  id: string;
  language: string;
  name: string;
};

export const Repo = ({ id, language, name }: Props) => (
  <View key={id}>
    <Text>{name}</Text>
    <Text>{language}</Text>
  </View>
);
Enter fullscreen mode Exit fullscreen mode

With our Repo component created, our ListRepos component becomes simpler:

import React from 'react';
import { View, ActivityIndicator } from 'react-native';
import { useGetRepos } from './useGetRepos';
import { Repo } from './Repo';

export const ListRepos = () => {
  const { isLoading, repos } = useGetRepos();

  if (isLoading) {
    return <ActivityIndicator size={'large'} color={'#4285F4'} />;
  }

  return (
    <View>
      {repos.map((item) => (
        <Repo {...item} />
      ))}
    </View>
  );
};
Enter fullscreen mode Exit fullscreen mode

We can keep improving. I'll leave a few challenges for you to implement and elevate your understanding of SRP:

  • Isolate the Axios call in another file and only call that functions in the useGetRerpos hook
  • The typing for the Repo component is the same as the one used in the hook, meaning it's repetitive. We can create a @types folder to share types across the application.

By implementing the Single Responsibility Principle (SRP) in our React Native development, we have achieved a more cohesive and modular structure. In the next post, we'll explore another principle to make our software design even better.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (1)

Collapse
 
retyui profile image
Davyd NRB

code blocks without code highlight is hard to read

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay