In this post, lets have a more in-depth look at how to actually get the current SharePoint context in your service, without passing it in explicitly.
All the code used in this post is available on GitHub: https://github.com/vman/SPFx-Service-Context-Demo
Building an SPFx service using ServiceScopes:
Suppose you want to create a service which you want to call from multiple SPFx webparts. The idea is that the code of your service should load on the page only once even if multiple web parts using the same service are added to the page. There is already some great information out there on building such kind of service in SPFx so I won't repeat it here. Have a look:
Share data through a SharePoint Framework service
Building shared code in SharePoint Framework - revisited
I myself have been working on building an SPFx service as an npm package and then using it in a webpart:
But before you go ahead and start using ServiceScopes to build your SPFx service, have a read through this Tech Note from the SPFx team:
To summarise, it is recommended to consider other alternatives first before using ServiceScopes. Other alternatives include explicitly passing in dependencies like SPHttpClient in the constructor of your service, or if your service has multiple dependencies, then build a class which has all the dependencies as properties and then pass an object of the class to your service's constructor.
While these recommendations would work in some scenarios, they might not be viable in all conditions. If you are building your service as an npm package, passing in the current context every time you want to use the service might be very burdensome. Ideally, your service should be able to determine all the information about the current context on its own. So lets have a look in this post on how do to that.
Quick note before moving ahead: Building library packages in SPFx is currently not available but it is on the roadmap. It would be nice to see the "build a library" option in the SPFx Yeoman generator. The UserVoice link for this request is here: https://sharepoint.uservoice.com/forums/329220-sharepoint-dev-platform/suggestions/19224202-add-support-for-library-packages-in-the-sharepoint
In this post, to keep things simple, I am going to build my service in the same package as my SPFx webpart. The idea is to demonstrate the concept of using ServiceScopes to get the current context. It would work exactly the same if the service was part of a different SPFx package. If you want to have a look at how this works, have a look at my github repo here: https://github.com/vman/SPFx-Service
Getting the current context in an SPFx service:
First, you need to build a service which accepts a ServiceScope object in the constructor. This is the only dependency your service will need. Also, you will not need to explicitly pass in this dependency. SharePoint Framework will handle this for you.
Here is my code for the service:
Now lets have a look at what is going on in the code:
First, we are importing the SPHttpClient class from the @microsoft/sp-http package and the PageContext class from the @microsoft/sp-page-context package.
These classes expose their own ServiceKeys, so in the constructor of our service, we are using those keys to grab an instance of these classes. These instances of classes will already be initialised thanks to the ServiceScope.whenFinished and ServiceScope.consume methods. We can then use the instances in the methods of our class.
Using the current web url to initialise PnP-JS-Core :
Consuming the service:
Now you have built your service, it is time to consume it from your SPFx web part. It is very straightforward, you just have to instantiate an object of your class using the ServiceScope.consume method and your are good to go. I am using async/await just to keep things simple, but using Promise.then will also work here:
Have a look at the complete code in this post here: https://github.com/vman/SPFx-Service-Context-Demo
Thanks for reading! Hope you have found this post helpful.