Skip to content

[Due for payment 2026-03-25] [Due for payment 2026-03-11] Split context providers to return State and Actions separately #80271

@mountiny

Description

@mountiny

Coming from here

Background:

Currently, our contexts return a single Context.Provider whose value prop is an object composed of both state and associated callback functions. In most cases, the context is paired with a dedicated hook that provides a convenient and type-safe way for components to consume it. Any change to the context value triggers a re-render of all subscribed components.

Problem

Components that consume only actions from a context provider are still subject to re-renders on context updates, even when they do not directly depend on the provider’s state. It causes higher number of re-renders all across the app.

Solution

Let’s separate State and Actions within the context providers. By exposing two independent providers—one for state and one for actions—we allow components to subscribe only to what they actually need:

  • Components that depend on state will re-render only when state changes.
  • Components that use only actions will remain stable and will not re-render in response to state updates.

This separation reduces unnecessary re-renders, improves performance, and makes the intent of each consumer more explicit. It also encourages a clearer mental model by distinguishing between data and behavior at the context level.

Example PR that has improved the performance of the SearchRouter: #79753

Additional note

This also presents an opportunity to do a small cleanup of our context usage. One area for improvement is standardizing how contexts are exposed to consumers by introducing dedicated hooks for each context. Currently, some contexts provide a custom hook (e.g. useExpensifyCardContext), while others are accessed directly via useContext in components (e.g. useContext(KYCWallContext)).

There is also a minor inconsistency in naming conventions, where some providers end with ContextProvider and others with Provider.

While none of this is critical, addressing it as part of this change would improve overall consistency and readability across the codebase.

Issue OwnerCurrent Issue Owner: @mallenexpensify

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionTaskWeeklyKSv2

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions