Recently I did some stuff with Facebooks' ReactJS. Quite soon I thought "Hey, wouldn't services be awesome" and I started to google. I found a working library, that worked for ES5 only.
When installing with NPM you will notice, that there are some error and it is not working. I have to compile the lib to ES5 to work with NPM. But due to some dependency-management, I keep getting Errors. Fork it and help me! Either you install it by downloading the lib via Github or you import the lib from the node module directly:
import {..whatever} from '(../)*node_modules/rservices/RServices'
npm install --save rservices
Import the relevant parts of RServices, depending on which you need in your current file.
import {DependencyManager, AbstractService, AbstractDIComponent} from 'path/to/RServices';
Then you can create a Service by extending the AbstractService
import {DependencyManager, AbstractService} from 'path/to/RServices';
class ExampleService extends AbstractService {
getInitialData() {
return {
foo: 1,
bar: "This value was delivered by the ExampleService."
}
}
incrementFoo() {
var foo = this.get('foo');
++foo;
this.set('foo', foo);
}
}
DependencyManager.register(ExampleService);
/**
*
* Another Example Service
*
**/
class Example2Service extends AbstractService {
getInitialData() {
return {
foo: 5,
bar: "This value was reversed by the ExampleService2 and reversed back by the filter."
}
}
doSomethingWithBar() {
var bar = this.get('bar');
bar = reverseString(bar);
this.set('bar', bar);
}
}
DependencyManager.register(Example2Service);
The getInitialData
method sets the default values of that service. incrementFoo
is a custom method.
Due to explicity the service has to be registered to the DependencyManager.
Then you write a component and extend the AbstractDIComponent
.
By adding the getComponentDependencies
method, you define which state variable should have the value of a service variable.
Then you also have the possibility to access that Service by calling this.$$services.SERVICE_NAME
.
import React from 'react';
import ReactDOM from 'react-dom';
import {AbstractDIComponent} from 'path/to/RServices';
class ExampleComponent extends AbstractDIComponent {
constructor(props) {
super(props);
this.state = {
bar: 0,
test: "test still contains its default value.",
something: ""
}
}
getComponentDependencies() {
return {
// state var bar should always have the same value as ExampleService.get('foo')
bar: [
'ExampleService',
'foo',
{
transformers: [(aNumber) => { return aNumber.toString(); }]
}
],
test: ['ExampleService', 'bar']
};
}
getPrivateComponentDependencies() {
return {
// state var bar should always have the same value as ExampleService.get('foo')
something: ['Example2Service', 'bar', {transformers: [reverseString]}]
};
}
componentDidMount() {
// access shared service
this.$$services.ExampleService.incrementFoo();
// access private service
this.$$privateServices.Example2Service.doSomethingWithBar();
}
render() {
var blockStyle = {display: 'block'};
return (
<div className="text">
<span style={blockStyle}>The value of "bar" is: {this.state.bar} ({getType(this.state.bar)})</span>
<span style={blockStyle}>The value of "test" is: {this.state.test} ({getType(this.state.test)})</span>
<span style={blockStyle}>The value of "something" is: {this.state.something} ({getType(this.state.something)})</span>
</div>
);
}
}
// DependencyManager.toggleProxyUse();
ReactDOM.render(React.createElement(ExampleComponent), document.querySelector('div'));
ES6 provides the Proxy
Class. If you're up to use React Services only with Browsers,
that support proxies (ATM only Firefox), you can enable proxies by calling DependencyManager.toggleProxyUse();
before rendering your components.
That way you can access properties of a service directly:
this.$$services.ExampleService.foo++
instead of
this.$$services.ExampleService.set('foo', this.$$services.ExampleService.get('foo') + 1);
If you want your components to have a non-shared Service, you can use the getPrivateComponentDependencies
Method of the AbstractDIComponent.
These services will then be stored in this.$$privateServices
.
If you want to use services but want to access methods only or just don't want to have a services variable linked to a component state variable, you can use the following two methods:
getServices() {
return [
//'ExampleService'
];
}
getPrivateServices() {
return [];
}
When a Servicevalue is updated, you might want to transform it somehow before passing it to the component.
E. g. your state variable should always contain a string but the value is delivered as integer, you can specify multiple transformer functions.
This is done in the getComponentDependencies
/getPrivateComponentDependencies
methods:
getComponentDependencies() {
return {
// state var bar should always have the same value as ExampleService.get('foo')
bar: [
'ExampleService',
'foo',
{
transformers: [(aNumber) => { return aNumber.toString(); }]
}
],
test: ['ExampleService', 'bar']
};
}