Having services in React application

Dennis Nerush picture Dennis Nerush · Mar 7, 2016 · Viewed 111.1k times · Source

I'm coming from the angular world where I could extract logic to a service/factory and consume them in my controllers.

I'm trying to understand how can I achieve the same in a React application.

Let's say that I have a component that validates user's password input (it's strength). It's logic is pretty complex hence I don't want to write it in the component it self.

Where should I write this logic? In a store if I'm using flux? Or is there a better option?

Answer

Wojtek Majerski picture Wojtek Majerski · Jun 22, 2018

The issue becomes extremely simple when you realize that an Angular service is just an object which delivers a set of context-independent methods. It's just the Angular DI mechanism which makes it look more complicated. The DI is useful as it takes care of creating and maintaining instances for you but you don't really need it.

Consider a popular AJAX library named axios (which you've probably heard of):

import axios from "axios";
axios.post(...);

Doesn't it behave as a service? It provides a set of methods responsible for some specific logic and is independent from the main code.

Your example case was about creating an isolated set of methods for validating your inputs (e.g. checking the password strength). Some suggested to put these methods inside the components which for me is clearly an anti-pattern. What if the validation involves making and processing XHR backend calls or doing complex calculations? Would you mix this logic with mouse click handlers and other UI specific stuff? Nonsense. The same with the container/HOC approach. Wrapping your component just for adding a method which will check whether the value has a digit in it? Come on.

I would just create a new file named say 'ValidationService.js' and organize it as follows:

const ValidationService = {
    firstValidationMethod: function(value) {
        //inspect the value
    },

    secondValidationMethod: function(value) {
        //inspect the value
    }
};

export default ValidationService;

Then in your component:

import ValidationService from "./services/ValidationService.js";

...

//inside the component
yourInputChangeHandler(event) {

    if(!ValidationService.firstValidationMethod(event.target.value) {
        //show a validation warning
        return false;
    }
    //proceed
}

Use this service from anywhere you want. If the validation rules change you need to focus on the ValidationService.js file only.

You may need a more complicated service which depends on other services. In this case your service file may return a class constructor instead of a static object so you can create an instance of the object by yourself in the component. You may also consider implementing a simple singleton for making sure that there is always only one instance of the service object in use across the entire application.