Introduction to the data layer
The WordPress data module (@wordpress/data) serves as a centralized hub for managing application state. It provides tools to manage data within and between distinct modules, designed to be simple enough for small plugins yet scalable for complex single-page applications.
The data module is built upon and shares many core principles with Redux, but includes several distinguishing characteristics that make it unique.
Installation
Install the data package:Core architectural principle
The data layer follows a key architectural decision:Data layer principle: Use
@wordpress/data (Redux-like stores). Edit entities through core-data actions (editEntityRecord / saveEditedEntityRecord), not direct state manipulation.Registering a store
Create and register a store usingcreateReduxStore and register:
Store configuration options
Reducer
A reducer is a function that accepts the previousstate and action and returns an updated state value:
Actions
The actions object describes all action creators available for your store:Dispatching actions is the primary mechanism for making changes to your state.
Selectors
The selectors object includes functions for accessing and deriving state values:Calling selectors is the primary mechanism for retrieving data from your state. They provide abstraction over raw data that’s typically more susceptible to change.
Resolvers
A resolver is a side-effect for a selector. If your selector result needs fulfillment from an external source, define a resolver:- Execute the first time a selector is called
- Receive the same arguments as the selector (excluding state)
- Can dispatch actions to fulfill selector requirements
- Work with thunks for asynchronous data flows
Using stores with React hooks
useSelect - Reading data
Retrieve data from stores usinguseSelect:
useDispatch - Writing data
Dispatch actions usinguseDispatch:
useRegistry - Accessing the registry
Access the registry directly for advanced use cases:Higher-order components
withSelect - Injecting data
withDispatch - Injecting actions
Core WordPress data stores
WordPress provides several built-in stores:Core data stores
Core data stores
core/blocks- Registered block types and block collectionscore/block-editor- Block editor state (selected blocks, settings, preferences)core/editor- Post editor state (current post, saving status, etc.)core(core-data) - WordPress entities via REST API (posts, pages, media, etc.)core/notices- User-facing notices and snackbarscore/viewport- Responsive breakpoints and device information
Working with core-data
Thecore store (core-data) manages WordPress entities:
Always use
editEntityRecord and saveEditedEntityRecord for editing entities, not direct state manipulation.Batching updates
Useregistry.batch() to batch multiple store updates:
Resolution state selectors
Track resolver execution state:Registry selectors
Create selectors that access other stores:Registry selectors can call selectors from other stores, enabling cross-store data derivation.
Comparison with Redux
The data module shares Redux core principles but differs in:Similarities
- Unidirectional data flow
- Pure reducer functions
- Action-based state updates
- Selector-based data access
Differences
Key differences from Redux
Key differences from Redux
- Modular stores: Separate but interdependent stores instead of a single global store
- Selectors as primary API: Selectors are the main entry point for data access
- Built-in async handling: Resolvers and thunks for asynchronous operations
- Subscribe optimizations: Subscribers only called when state actually changes
- Split HOCs:
withSelectandwithDispatchinstead of singleconnect
Async data flows
Handle asynchronous operations with thunks:Generic stores
Integrate existing Redux stores or create completely custom stores:Best practices
Data layer best practices
Data layer best practices
- Use selectors for all data access - Never access state directly
- Keep reducers pure - No side effects, API calls, or mutations
- Use resolvers for data fetching - Let resolvers handle async operations
- Batch related updates - Use
registry.batch()for multiple dispatches - Memoize expensive selectors - Use
createSelectorfor computed data - Define clear dependencies - Always specify dependency arrays in hooks
- Edit entities correctly - Use
editEntityRecordfor core-data entities - Track resolution state - Use resolution selectors for loading states
Next steps
- Learn about Components for building UIs
- Explore Block Editor Architecture
- Understand Extensibility patterns
- Deep dive into Blocks