-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Framework: Introduce the data module (#3832)
- Loading branch information
1 parent
7c917c9
commit 5c33f6f
Showing
27 changed files
with
291 additions
and
128 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
Data | ||
==== | ||
|
||
The more WordPress UI moves to the client, the more there's a need for a centralized data module allowing data management and sharing between several WordPress modules and plugins. | ||
|
||
This module holds a global state variable and exposes a "Redux-like" API containing the following methods: | ||
|
||
|
||
### `wp.data.registerReducer( reducer: function )` | ||
|
||
If your module or plugin needs to store and manipulate client-side data, you'll have to register a "reducer" to do so. A reducer is a function taking the previous `state` and `action` and returns an update `state`. You can learn more about reducers on the [Redux Documentation](https://redux.js.org/docs/basics/Reducers.html) | ||
|
||
### `wp.data.getState()` | ||
|
||
A simple function to returns the JS object containing the state of all the WP Modules. | ||
This function is present for convenience to use things like `react-redux`. | ||
You should not use rely on other modules state since the state object's shape may change over time breaking your module. | ||
An official way to expose your module's state will be added later. | ||
|
||
### `wp.data.subscribe( listener: function )` | ||
|
||
Registers a `listener` function called everytime the state is updated. | ||
|
||
### `wp.data.dispatch( action: object )` | ||
|
||
The dispatch function should be called to trigger the registered reducers function and update the state. An `action` object should be passed to this action. This action is passed to the registered reducers in addition to the previous state. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { createStore, combineReducers } from 'redux'; | ||
import { flowRight } from 'lodash'; | ||
|
||
/** | ||
* Module constants | ||
*/ | ||
const reducers = {}; | ||
const enhancers = []; | ||
if ( window.__REDUX_DEVTOOLS_EXTENSION__ ) { | ||
enhancers.push( window.__REDUX_DEVTOOLS_EXTENSION__() ); | ||
} | ||
|
||
const initialReducer = () => ( {} ); | ||
const store = createStore( initialReducer, {}, flowRight( enhancers ) ); | ||
|
||
/** | ||
* Registers a new sub reducer to the global state | ||
* | ||
* @param {String} key Reducer key | ||
* @param {Object} reducer Reducer function | ||
*/ | ||
export function registerReducer( key, reducer ) { | ||
reducers[ key ] = reducer; | ||
store.replaceReducer( combineReducers( reducers ) ); | ||
} | ||
|
||
export const subscribe = store.subscribe; | ||
|
||
export const dispatch = store.dispatch; | ||
|
||
export const getState = store.getState; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { registerReducer, getState } from '../'; | ||
|
||
describe( 'store', () => { | ||
it( 'Should append reducers to the state', () => { | ||
const reducer1 = () => 'chicken'; | ||
const reducer2 = () => 'ribs'; | ||
|
||
registerReducer( 'red1', reducer1 ); | ||
expect( getState() ).toEqual( { red1: 'chicken' } ); | ||
|
||
registerReducer( 'red2', reducer2 ); | ||
expect( getState() ).toEqual( { | ||
red1: 'chicken', | ||
red2: 'ribs', | ||
} ); | ||
} ); | ||
} ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/** | ||
* WordPress Dependencies | ||
*/ | ||
import { registerReducer } from '@wordpress/data'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { PREFERENCES_DEFAULTS } from './defaults'; | ||
import reducer from './reducer'; | ||
import { withRehydratation, loadAndPersist } from './persist'; | ||
import enhanceWithBrowserSize from './browser'; | ||
import store from './store'; | ||
|
||
/** | ||
* Module Constants | ||
*/ | ||
const STORAGE_KEY = `GUTENBERG_PREFERENCES_${ window.userSettings.uid }`; | ||
|
||
registerReducer( 'core/editor', withRehydratation( reducer, 'preferences' ) ); | ||
loadAndPersist( store, 'preferences', STORAGE_KEY, PREFERENCES_DEFAULTS ); | ||
enhanceWithBrowserSize( store ); | ||
|
||
export default store; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { get } from 'lodash'; | ||
|
||
/** | ||
* Adds the rehydratation behavior to redux reducers | ||
* | ||
* @param {Function} reducer The reducer to enhance | ||
* @param {String} reducerKey The reducer key to persist | ||
* | ||
* @return {Function} Enhanced reducer | ||
*/ | ||
export function withRehydratation( reducer, reducerKey ) { | ||
// EnhancedReducer with auto-rehydration | ||
const enhancedReducer = ( state, action ) => { | ||
const nextState = reducer( state, action ); | ||
|
||
if ( action.type === 'REDUX_REHYDRATE' ) { | ||
return { | ||
...nextState, | ||
[ reducerKey ]: action.payload, | ||
}; | ||
} | ||
|
||
return nextState; | ||
}; | ||
|
||
return enhancedReducer; | ||
} | ||
|
||
/** | ||
* Loads the initial state and persist on changes | ||
* | ||
* This should be executed after the reducer's registration | ||
* | ||
* @param {Object} store Store to enhance | ||
* @param {String} reducerKey The reducer key to persist (example: reducerKey.subReducerKey) | ||
* @param {String} storageKey The storage key to use | ||
* @param {Object} defaults Default values of the reducer key | ||
*/ | ||
export function loadAndPersist( store, reducerKey, storageKey, defaults = {} ) { | ||
// Load initially persisted value | ||
const persistedString = window.localStorage.getItem( storageKey ); | ||
if ( persistedString ) { | ||
const persistedState = { | ||
...defaults, | ||
...JSON.parse( persistedString ), | ||
}; | ||
|
||
store.dispatch( { | ||
type: 'REDUX_REHYDRATE', | ||
payload: persistedState, | ||
} ); | ||
} | ||
|
||
// Persist updated preferences | ||
let currentStateValue = get( store.getState(), reducerKey ); | ||
store.subscribe( () => { | ||
const newStateValue = get( store.getState(), reducerKey ); | ||
if ( newStateValue !== currentStateValue ) { | ||
currentStateValue = newStateValue; | ||
window.localStorage.setItem( storageKey, JSON.stringify( currentStateValue ) ); | ||
} | ||
} ); | ||
} |
Oops, something went wrong.