Having services in React application
Asked Answered
B

13

346

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?

Bonsai answered 7/3, 2016 at 22:53 Comment(3)
No. Only client side logic that should not be directly in the component. The password strength checker is just an exampleBonsai
If you have many such functions you could store them in a helper file and just require it into your component file for usage. If it's a single function that is relevant solely to that component it should probably live there no matter the complexity.Lorenlorena
You can accomplish anything like services with Context APIFabrikoid
P
91

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.

Providers

If there's a bit more configuration necessary, you can use a Provider/Consumer model. A provider is a high level component that wraps somewhere close to and underneath the top application object (the one you mount) and supplies a part of itself, or a property configured in the top layer, to the context API. I then set my container elements to consume the context.

The parent/child context relations don't have to be near each other, just the child has to be descended in some way. Redux stores and the React Router function in this way. I've used it to provide a root restful context for my rest containers (if I don't provide my own).

(note: the context API is marked experimental in the docs, but I don't think it is any more, considering what's using it).

//An example of a Provider component, takes a preconfigured restful.js
//object and makes it available anywhere in the application
export default class RestfulProvider extends React.Component {
	constructor(props){
		super(props);

		if(!("restful" in props)){
			throw Error("Restful service must be provided");
		}
	}

	getChildContext(){
		return {
			api: this.props.restful
		};
	}

	render() {
		return this.props.children;
	}
}

RestfulProvider.childContextTypes = {
	api: React.PropTypes.object
};

Middleware

A further way I haven't tried, but seen used, is to use middleware in conjunction with Redux. You define your service object outside the application, or at least, higher than the redux store. During store creation, you inject the service into the middleware and the middleware handles any actions that affect the service.

In this way, I could inject my restful.js object into the middleware and replace my container methods with independent actions. I'd still need a container component to provide the actions to the form view layer, but connect() and mapDispatchToProps have me covered there.

The new v4 react-router-redux uses this method to impact the state of the history, for example.

//Example middleware from react-router-redux
//History is our service here and actions change it.

import { CALL_HISTORY_METHOD } from './actions'

/**
 * This middleware captures CALL_HISTORY_METHOD actions to redirect to the
 * provided history object. This will prevent these actions from reaching your
 * reducer or any middleware that comes after this one.
 */
export default function routerMiddleware(history) {
  return () => next => action => {
    if (action.type !== CALL_HISTORY_METHOD) {
      return next(action)
    }

    const { payload: { method, args } } = action
    history[method](...args)
  }
}
Pechora answered 14/7, 2017 at 18:30 Comment(7)
what is the usage for container example?Sounder
I'm not advocating it, but if you wanted to go down the service locator path (something similar to Angular), you could add some kind of "injector/container" provider that you resolve services from (having previously registered them).Protrusion
React hooks comes to the rescue. With Hooks you can write reusable logic without writing a class. reactjs.org/docs/…Baptize
Fantastic answer. Per @RajaMalik 's comment, I actually found myself using hooks to provide services this very often and wound up writing a tiny library to encapsulate doing so: github.com/traviskaufman/react-service-containerAssiniboine
I don't agree with the 'correct' way. This is a pattern I see abused in React a lot. Everything becomes described as components and the lines between the semantic structure of the XML becomes blurred with application/business logic. That's not to say they don't have a role (I've implemented <Form>, <Input>, etc. wrapper comps to build a custom form library), I just don't see why pure js functions and services would be less appropriate here. The same goes for your middlewear solution which assumes a centralized store. These types of problems can be decoupled from the framework.Phlox
What is "the first answer"? Please make your answer independent of voting or acceptance by linking directly to other resources, such as answers.Abrahamsen
"write a ValidatorContainer, which will have that function as a property, and wrap the form in it" What does "it" stand for here? The wording is very confusing.Yoghurt
A
262

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.

Armond answered 21/6, 2018 at 23:30 Comment(11)
This is the way that I would do it too. I am quite surprised that this answer has so few votes for it, as this feels to be the way with least friction. If your service depends on other services, then again, it would be importing those other services via their modules. Furthermore modules are, by definition, singletons, so there is actually no further work needed to "implement it as a simple singleton" - you get that behaviour for free :)Schou
+1 - Nice answer if you're only using services that provide functions. However, Angular's service are classes that are defined once, thus providing more features than just delivering functions. You can cache objects as service class parameter, for example.Stereometry
In your example, could secondValidationMethod call firstValidationMethod?Upolu
This is a good answer, except it's not "reactive". The DOM will not update on variable changes within the service.Ctn
What about dependency injection though? The service is impossible to mock in your component unless you inject it somehow. Perhaps having a top-level "container" global object that has each service as a field would get around this. Then in your tests, you can override the container fields with mocks for the services you want to mock.Fleawort
@Ctn One solution to that issue is reactive extensions (observables). Subscribe to an observable stream returned from the service and use Subjects to "push" changes down through to a component. Personally, I prefer this answer because it lets me move business logic outside of a component, keeping my components as small as possible and not manually handling data. Less Complex pieces => less bugs/easier to maintain.Rudimentary
I'd agree to this only partially. This will work for just stateless function logic. How would you achieve the task of storing variables in memory, for which usually use services in angular.Worldbeater
@sasebot yes this is for functional code. If you want to store variables (outside of component state ofcourse) you are free to use implement the observer pattern ofcourse. But i prefer to use actions and reducers, and keeping all state in Redux. All logic is 100% pure functions in my React projects.Heterolysis
Yeah but then, you can't use react hooks. For example, your function logout cannot use "useNavigate()" from react-router. So it is very limited. I think today, the answer would be to create a custom hook. Another solution could be to create a High Order Component, but i feel like it would be quite cumbersome.Glass
As many have commented, this is not at all what Angular services are! Angular services have scope, state and lifetime! You suggestion have one scope, no state and obviously lifetime is not applicable to pure functions either.Walloping
When it comes to answering the question with any rigor for the topic about "Where do I keep shared state". React is has no answer except for some myriad of support libraries. Everyone has their own unique snowflake approach, but it really just comes down to "we use SINGLETONS". If you actually need true shared state you'd just us DI and angular to do it. The answers are either create static helper functions, or instantiate a class in each component (or HOC something- psshhh). Sure you're sharing the code, but NOT the state if everyone has a separate instance. That's what DI gives you.Frankfurter
P
91

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.

Providers

If there's a bit more configuration necessary, you can use a Provider/Consumer model. A provider is a high level component that wraps somewhere close to and underneath the top application object (the one you mount) and supplies a part of itself, or a property configured in the top layer, to the context API. I then set my container elements to consume the context.

The parent/child context relations don't have to be near each other, just the child has to be descended in some way. Redux stores and the React Router function in this way. I've used it to provide a root restful context for my rest containers (if I don't provide my own).

(note: the context API is marked experimental in the docs, but I don't think it is any more, considering what's using it).

//An example of a Provider component, takes a preconfigured restful.js
//object and makes it available anywhere in the application
export default class RestfulProvider extends React.Component {
	constructor(props){
		super(props);

		if(!("restful" in props)){
			throw Error("Restful service must be provided");
		}
	}

	getChildContext(){
		return {
			api: this.props.restful
		};
	}

	render() {
		return this.props.children;
	}
}

RestfulProvider.childContextTypes = {
	api: React.PropTypes.object
};

Middleware

A further way I haven't tried, but seen used, is to use middleware in conjunction with Redux. You define your service object outside the application, or at least, higher than the redux store. During store creation, you inject the service into the middleware and the middleware handles any actions that affect the service.

In this way, I could inject my restful.js object into the middleware and replace my container methods with independent actions. I'd still need a container component to provide the actions to the form view layer, but connect() and mapDispatchToProps have me covered there.

The new v4 react-router-redux uses this method to impact the state of the history, for example.

//Example middleware from react-router-redux
//History is our service here and actions change it.

import { CALL_HISTORY_METHOD } from './actions'

/**
 * This middleware captures CALL_HISTORY_METHOD actions to redirect to the
 * provided history object. This will prevent these actions from reaching your
 * reducer or any middleware that comes after this one.
 */
export default function routerMiddleware(history) {
  return () => next => action => {
    if (action.type !== CALL_HISTORY_METHOD) {
      return next(action)
    }

    const { payload: { method, args } } = action
    history[method](...args)
  }
}
Pechora answered 14/7, 2017 at 18:30 Comment(7)
what is the usage for container example?Sounder
I'm not advocating it, but if you wanted to go down the service locator path (something similar to Angular), you could add some kind of "injector/container" provider that you resolve services from (having previously registered them).Protrusion
React hooks comes to the rescue. With Hooks you can write reusable logic without writing a class. reactjs.org/docs/…Baptize
Fantastic answer. Per @RajaMalik 's comment, I actually found myself using hooks to provide services this very often and wound up writing a tiny library to encapsulate doing so: github.com/traviskaufman/react-service-containerAssiniboine
I don't agree with the 'correct' way. This is a pattern I see abused in React a lot. Everything becomes described as components and the lines between the semantic structure of the XML becomes blurred with application/business logic. That's not to say they don't have a role (I've implemented <Form>, <Input>, etc. wrapper comps to build a custom form library), I just don't see why pure js functions and services would be less appropriate here. The same goes for your middlewear solution which assumes a centralized store. These types of problems can be decoupled from the framework.Phlox
What is "the first answer"? Please make your answer independent of voting or acceptance by linking directly to other resources, such as answers.Abrahamsen
"write a ValidatorContainer, which will have that function as a property, and wrap the form in it" What does "it" stand for here? The wording is very confusing.Yoghurt
S
58

I needed some formatting logic to be shared across multiple components and as an Angular developer also naturally leaned towards a service.

I shared the logic by putting it in a separate file

function format(input) {
    //convert input to output
    return output;
}

module.exports = {
    format: format
};

and then imported it as a module

import formatter from '../services/formatter.service';

//then in component

    render() {

        return formatter.format(this.props.data);
    }
Schizogenesis answered 8/11, 2017 at 22:35 Comment(6)
This is a good idea as even mentioned in React document: reactjs.org/docs/composition-vs-inheritance.html If you want to reuse non-UI functionality between components, we suggest extracting it into a separate JavaScript module. The components may import it and use that function, object, or a class, without extending it.Deeprooted
Where is the dependency injection in this answer?Epilate
How do you mock it in component tests?Polloch
This won't work in SSR, as it will be an unsecured global.Luiseluiza
Where is formatter defined?Yoghurt
formatter is an alias for the imported file formatter.serviceSchizogenesis
S
33

Keep in mind that the purpose of React is to better couple things that logically should be coupled. If you're designing a complicated "validate password" method, where should it be coupled?

Well you're going to need to use it every time the user needs to input a new password. This could be on the registration screen, a "forgot password" screen, an administrator "reset password for another user" screen, etc.

But in any of those cases, it's always going to be tied to some text input field. So that's where it should be coupled.

Make a very small React component that consists solely of an input field and the associated validation logic. Input that component within all of the forms that might want to have a password input.

It's essentially the same outcome as having a service/factory for the logic, but you're coupling it directly to the input. So you now never need to tell that function where to look for it's validation input, as it is permanently tied together.

Silence answered 8/3, 2016 at 4:24 Comment(12)
What it is bad practice to couple logic and UI. In order to change the logic I will have to touch the componentBonsai
React fundamentally challenges that assumption that you are making. It is in stark contrast to traditional MVC architecture. This video does a pretty good job of explaining why that is (relevant section starts around 2 minutes in).Silence
What if the same validation logic also needs to be applied to a text area element? The logic still needs to be extracted into a shared file. I don't think out of box there is any equivalence from react library. Angular Service are injectables, and Angular framework is built on top of dependency injection design pattern, which allow the instances of the dependencies managed by Angular. When a service is injected, there usually is a singleton in the provided scope, to have the same service in React, a 3rd party DI lib needs to be introduced to the application.Kohl
@ZhenyangHua - why would a text area element need to validate the format of a format?Albaugh
@ZhenyangHua: If you like the way angular does things, then use angular. React is different and follows different design patterns. You shouldn't expect it to conform to angular's standards or patterns.Silence
@gravityplanx I enjoy using React. This is not angular pattern, this is software design pattern. I like to keep my mind opening while borrowing things I like from other good parts.Kohl
@gravityplanx I agree that you've provided one particular case of a piece of logic that is associated with a UI component. But that's not true in general! What about all the other cases.Clothe
@ZhenyangHua why would you need to use a 3rd party DI lib, surely the ES6 Module system does this job?Schou
@MickeyPuri ES6 modules is not the same as Dependency Injection.Ctenophore
@MickeyPuri module system is the way how the es6 engine connecting different files together to the engine knows where to read the code. DI is runtime behavior, it has nothing to do with compiler/engine.Kohl
@JakeHaller-Roby Thanks for sharing the video. Great tip! At about 12:30 minutes Pete Hunt mentions; "Only put display logic in your component". I'm not saying that it would be wrong to put the logic for validating the password in a component. But I don't think that this particular code is display logic.Marlin
I think you're convincing yourself of your own sophistry there. A little coupling here, a little coupling there, what's the harm right? Then you wake up and realize you've screwed yourself unnecessarily. It's hard to convince people who've never experienced it when they are so convinced it's not an issue. But, React has pulled the rug over everyone's eyes with this sophistry and virtues of the virtual dom. Just look at the example of "ES6 modules are the same thing as DI" argument here. You fundamentally don't know what DI is if you think you can make that argument with a straight face.Frankfurter
D
17

Same situation: Having done multiple Angular projects and moving to React, not having a simple way to provide services through DI seems like a missing piece (the particulars of the service aside).

Using context and ES7 decorators we can come close:

https://jaysoo.ca/2015/06/09/react-contexts-and-dependency-injection/

Seems these guys have taken it a step further / in a different direction:

http://blog.wolksoftware.com/dependency-injection-in-react-powered-inversifyjs

Still feels like working against the grain. Will revisit this answer in 6 months time after undertaking a major React project.

EDIT: Back 6 months later with some more React experience. Consider the nature of the logic:

  1. Is it tied (only) to UI? Move it into a component (accepted answer).
  2. Is it tied (only) to state management? Move it into a thunk.
  3. Tied to both? Move to separate file, consume in component through a selector and in thunks.

Some also reach for HOCs for reuse but for me the above covers almost all use cases. Also, consider scaling state management using ducks to keep concerns separate and state UI-centric.

Dalenedalenna answered 12/10, 2017 at 14:37 Comment(2)
Imho I think there is a simple way to provide services thru DI, by using the ES6 Module systemSchou
@MickeyPuri, ES6 module DI wouldn't include the hierarchical nature of Angular DI, ie. parents (in DOM) instantiating and overriding services supplied to child components. Imho ES6 module DI compare closer to backend DI systems like Ninject and Structuremap, sitting apart from, rather than being based on, the DOM component hierarchy. But I'd like to hear your thoughts on it.Dalenedalenna
B
14

I also came from Angular.js area and the services and factories in React.js are more simple.

You can use plain functions or classes, callback style and event Mobx like me :)

// Here we have Service class > dont forget that in JS class is Function
class HttpService {
  constructor() {
    this.data = "Hello data from HttpService";
    this.getData = this.getData.bind(this);
  }

  getData() {
    return this.data;
  }
}


// Making Instance of class > it's object now
const http = new HttpService();


// Here is React Class extended By React
class ReactApp extends React.Component {
  state = {
    data: ""
  };

  componentDidMount() {
    const data = http.getData();

    this.setState({
      data: data
    });
  }

  render() {
    return <div>{this.state.data}</div>;
  }
}

ReactDOM.render(<ReactApp />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  
  <div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

</body>
</html>

Here is simple example :

Bonfire answered 17/1, 2018 at 1:26 Comment(1)
React.js is UI library to render and organize UI components. When it comes to services that can help us add additional functionalities then we should create collections of functions, functional objects or classes. I found classes very useful but know I am playing also with functional style that can be also used for creating a helpers for adding advantaged functionality that is out of the Reac.js scope.Bonfire
R
12

I am from Angular as well and trying out React, as of now, one recommended(?) way seems to be using High-Order Components:

A higher-order component (HOC) is an advanced technique in React for reusing component logic. HOCs are not part of the React API, per se. They are a pattern that emerges from React’s compositional nature.

Let's say you have input and textarea and like to apply the same validation logic:

const Input = (props) => (
  <input type="text"
    style={props.style}
    onChange={props.onChange} />
)
const TextArea = (props) => (
  <textarea rows="3"
    style={props.style}
    onChange={props.onChange} >
  </textarea>
)

Then write a HOC that does validate and style wrapped component:

function withValidator(WrappedComponent) {
  return class extends React.Component {
    constructor(props) {
      super(props)

      this.validateAndStyle = this.validateAndStyle.bind(this)
      this.state = {
        style: {}
      }
    }

    validateAndStyle(e) {
      const value = e.target.value
      const valid = value && value.length > 3 // shared logic here
      const style = valid ? {} : { border: '2px solid red' }
      console.log(value, valid)
      this.setState({
        style: style
      })
    }

    render() {
      return <WrappedComponent
        onChange={this.validateAndStyle}
        style={this.state.style}
        {...this.props} />
    }
  }
}

Now those HOCs share the same validating behavior:

const InputWithValidator = withValidator(Input)
const TextAreaWithValidator = withValidator(TextArea)

render((
  <div>
    <InputWithValidator />
    <TextAreaWithValidator />
  </div>
), document.getElementById('root'));

I created a simple demo.

Edit: Another demo is using props to pass an array of functions so that you can share logic composed by multiple validating functions across HOCs like:

<InputWithValidator validators={[validator1,validator2]} />
<TextAreaWithValidator validators={[validator1,validator2]} />

Edit2: React 16.8+ provides a new feature, Hook, another nice way to share logic.

const Input = (props) => {
  const inputValidation = useInputValidation()

  return (
    <input type="text"
    {...inputValidation} />
  )
}

function useInputValidation() {
  const [value, setValue] = useState('')
  const [style, setStyle] = useState({})

  function handleChange(e) {
    const value = e.target.value
    setValue(value)
    const valid = value && value.length > 3 // shared logic here
    const style = valid ? {} : { border: '2px solid red' }
    console.log(value, valid)
    setStyle(style)
  }

  return {
    value,
    style,
    onChange: handleChange
  }
}

https://stackblitz.com/edit/react-shared-validation-logic-using-hook?file=index.js

Robles answered 9/12, 2017 at 19:12 Comment(6)
Thank you. I really learned from this solution. What if I need to have more than one validator. For example in addition to 3 letters validator, what if I want to have another validator that makes sure that no numbers are entered. Could we compose validators?Geof
@YoussefSherif You can prepare multiple validating functions and pass them as props of HOC, see my edit for another demo.Robles
so HOC is basically container component?Sounder
Yes, from React doc: "Note that a HOC doesn’t modify the input component, nor does it use inheritance to copy its behavior. Rather, a HOC composes the original component by wrapping it in a container component. A HOC is a pure function with zero side-effects."Robles
The requirement was to inject logic, I do not see why we need a HOC to do this. While you can do it with a HOC, it feels an over complicated. My understanding of HOCs is when there is also some additional state that needs to be added and managed, ie not pure logic (which was the case here).Schou
@MickeyPuri Having a state in my code is the reason you call it 'not pure'?Robles
T
4

If you are still looking for a service like Angular, you can try the react-rxbuilder library

You can use @Injectable to register the service, and then you can use useService or CountService.ins to use the service in the component

import { RxService, Injectable, useService } from "react-rxbuilder";

@Injectable()
export class CountService {
  static ins: CountService;

  count = 0;
  inc() {
    this.count++;
  }
}

export default function App() {
  const [s] = useService(CountService);
  return (
    <div className="App">
      <h1>{s.count}</h1>
      <button onClick={s.inc}>inc</button>
    </div>
  );
}

// Finally use `RxService` in your root component
render(<RxService>{() => <App />}</RxService>, document.getElementById("root"));

Precautions

  • Depends on rxjs and typescript
  • Cannot use arrow functions in the service
Twowheeler answered 28/7, 2021 at 11:53 Comment(0)
F
3

Service is not limited to Angular, even in Angular2+,

Service is just collection of helper functions...

And there are many ways to create them and reuse them across the application...

1) They can be all separated function which are exported from a js file, similar as below:

export const firstFunction = () => {
   return "firstFunction";
}

export const secondFunction = () => {
   return "secondFunction";
}
//etc

2) We can also use factory method like, with collection of functions... with ES6 it can be a class rather than a function constructor:

class myService {

  constructor() {
    this._data = null;
  }

  setMyService(data) {
    this._data = data;
  }

  getMyService() {
    return this._data;
  }

}

In this case you need make an instance with new key...

const myServiceInstance = new myService();

Also in this case, each instance has it's own life, so be careful if you want to share it across, in that case you should export only the instance you want...

3) If your function and utils not gonna be shared, you can even put them in React component, in this case, just as function in your react component...

class Greeting extends React.Component {
  getName() {
    return "Alireza Dezfoolian";
  }

  render() {
    return <h1>Hello, {this.getName()}</h1>;
  }
}

4) Another way you may handle things, could be using Redux, it's a temporary store for you, so if you have it in your React application, it can help you with many getter setter functions you use... It's like a big store that keep tracks of your states and can share it across your components, so can get rid of many pain for getter setter stuffs we use in the services...

It's always good to do a DRY code and not repeating what needs to be used to make the code reusable and readable, but don't try to follow Angular ways in React app, as mentioned in item 4, using Redux can reduce your need of services and you limit using them for some reuseable helper functions like item 1...

Fronnia answered 12/5, 2018 at 4:51 Comment(2)
"Dont follow Angular ways in React".. ahem Angular promotes using Redux and stream the store to the presentational components using Observables and Redux-like state management like RxJS/Store. .. did you mean AngularJS? Cuz that's another thingCtenophore
"don't try to follow Angular ways " Cannot agree, while state management in Angular 2+ is much better you should reuse the best practices as much as possible.Allembracing
V
2

I am in the same boat like you. In the case you mention, I would implement the input validation UI component as a React component.

I agree the implementation of the validation logic itself should (must) not be coupled. Therefore I would put it into a separate JS module.

That is, for logic that should not be coupled use a JS module/class in separate file, and use require/import to de-couple the component from the "service".

This allows for dependency injection and unit testing of the two independently.

Villalobos answered 13/9, 2016 at 5:3 Comment(0)
S
2

In the React world we have two types of logic: Stateful and stateless. Now this is the main concept to grasp when starting with React. That here we update state which should update UI as opposed to Angular's direct updates of dom. The two types of logics are:

  1. That do not depend on state changes, i.e. static logic which doesn't need to re-render something based on state changes. For such cases just create regular js files and import them like a library or helper methods
  2. If you have some code that depends on state and u need to resuse it then two options - hocs and the newer hooks. Hooks are a bit hard to wrap our heads around but basically they would force their parent to rerender if their internal state changes so any stateful logic can be defined and reused in different components, and each hook instance would have its own isolated scope.

It's a little bit of a thinking shift to understand state and declarative components but feel free to ask followup questions in comments

Standby answered 24/10, 2021 at 8:37 Comment(1)
Finding the correct use case for a hook is tough. They can easily be overused as well, once you realize the powers of them.Sprouse
B
1

or you can inject the class inheritance "http" into React Component

via props object.

  1. update :

    ReactDOM.render(<ReactApp data={app} />, document.getElementById('root'));
    
  2. Simply edit React Component ReactApp like this:

    class ReactApp extends React.Component {
    
    state = {
    
        data: ''
    
    }
    
        render(){
    
        return (
            <div>
            {this.props.data.getData()}      
            </div>
    
        )
        }
    }
    
Bonfire answered 17/1, 2018 at 1:31 Comment(0)
M
0

It is possible to use export keyword to use functions from file which contains necessary methods.

Let me show an example. Let's say we have a file called someService.ts:

export const foo = (formId: string) => {
    // ... the code is omitted for the brevity
}


export const bar = (): Entity[] => [
    // ... the code is omitted for the brevity
]

export default {
    foo,
    bar,
}

Then we can use this service in component like this:

import {
    foo,
    bar,
} from './someService'

const InnerOrderModal: FC = observer(() => {
    const handleFormClick = (value: unknown, item: any) => {
    foo(item.key)
    bar()
    
    return <></>
}
Malamute answered 4/5, 2022 at 16:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.