Having Services in React Application

Having Services in React Application

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?

6

13 Answers

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.

11

The first answer doesn't reflect the current Container vs Presenter paradigm.

If you need to do something, like validate a password, you'd likely have a function that does it. You'd be passing that function to your reusable view as a prop.

Containers

So, the correct way to do it is to write a ValidatorContainer, which will have that function as a property, and wrap the form in it, passing the right props in to the child. When it comes to your view, your validator container wraps your view and the view consumes the containers logic.

Validation could be all done in the container's properties, but it you're using a 3rd party validator, or any simple validation service, you can use the service as a property of the container component and use it in the container's methods. I've done this for restful components and it works very well.

Robert Thorne
Author

Robert Thorne

Robert Thorne covers electric vehicle innovations, autonomous driving systems, global mobility trends, and automotive engineering developments.