Solving the Ghost Context Issue in SPFx using PnPJs v4
- Vincent P.
- Jul 3
- 3 min read
Developing SPFx solutions with multiple web parts can be incredibly powerful, but with great flexibility comes great complexity.
One common headache? The infamous "ghost context" issue. If you've ever switched between SharePoint pages that each host web parts from the same solution and encountered unpredictable behavior, you're not alone.
In this article, I'll walk you through a practical and elegant solution I implemented using PnPjs v4 to manage and update context correctly across web parts, ensuring solid, predictable performance.

The Ghost Context Problem (and Why It Matters)
Let’s set the stage. In a typical multi-web part SPFx solution, you might share helper methods or services across web parts.
If you're not careful with how the SharePoint context is passed and cached, you risk encountering "ghost contexts", where a previously loaded context haunts your web part even after navigating to a different page.
This bug is subtle, but it can lead to major functionality issues when making Graph or SharePoint REST calls and crash your entire webpart.
The root cause often lies in the solution-level caching of clients, without proper reinitialization of the context when switching web parts or pages.
PnPjs's Suggested Approach With PnPjs v4
The team suggests a minimal setup for initializing SP and Graph clients:
let _sp: SPFI;
let _graph: GraphFI;
export const getSP = (context?: WebPartContext): SPFI => {
if (_sp === undefined || _sp === null) {
_sp = spfi().using(spSPFx(context as ISPFXContext));
}
return _sp;
};
export const getGraph = (context?: WebPartContext): GraphFI => {
if (_graph === undefined || _graph === null) {
_graph = graphfi().using(graphSPFx(context as ISPFXContext));
}
return _graph;
};While this works well in many cases, it doesn’t update the context once it's set, which is problematic in multi-web part solutions where each web part may live on different pages and require its own fresh context.
My Improved Approach
Dynamic Context Handling To solve this problem, I created a context manager that updates the WebPartContext whenever it's provided.
This ensures the clients are always initialized with the current and relevant context, eliminating the ghost context issue entirely.
let _sp: SPFI;
let _graph: GraphFI;
let _webPartContext: WebPartContext;
export const getContext = (context?: WebPartContext): WebPartContext => {
if (!!context) {
_webPartContext = context;
}
return _webPartContext;
};
export const getSP = (context?: WebPartContext): SPFI => {
if (!!context) {
_sp = spfi().using(spSPFx(context as ISPFXContext));
}
return _sp;
};
export const getGraph = (context?: WebPartContext): GraphFI => {
if (!!context) {
_graph = graphfi().using(graphSPFx(context as ISPFXContext));
}
return _graph;
};Why This Works Better
Context Is Always Current: Each time a web part provides a new context, it's set and used immediately—no outdated context lingers.
Solution-Level Initialization with Flexibility:Â SP and Graph clients are stored at the solution level, but always initialized with the latest web part context.
Clean and Maintainable:Â Centralizing context updates simplifies your architecture and reduces the need for prop-drilling.
Tips to Get the Most Out of It
Always call getContext(this.context), getSP(this.context) and getGraph(this.context) early in your web part’s lifecycle
protected async onInit(): Promise<void> {
await super.onInit();
getContext(this.context);
getSP(this.context);
getGraph(this.context);
return this._getEnvironmentMessage().then(message => {
this._environmentMessage = message;
});
}Conclusion
This dynamic context handling pattern offers a robust fix to the ghost context issue and is especially helpful in solutions with multiple web parts deployed across different pages.
By using the latest context whenever available, your SPFx solution remains consistent and bug-free.
Need help optimizing your SPFx architecture? Our team specializes in scalable, maintainable SharePoint and Power Platform solutions—reach out and let’s elevate your digital workplace!
Link to the library: PnP/PnPjs