Commit 4ca56948 authored by Robert Knight's avatar Robert Knight

Align store module naming with Redux terminology

Rename several fields of the configuration object for store modules to
better align with the associated Redux concepts. This should make it
easier for newcomers to the code to understand it if they already have
some familiarity with Redux.

 - Rename the `init` function to `initialState`
 - Rename the `update` map to `reducers`
 - Rename the `actions` map to `actionCreators`
parent 7563a60c
......@@ -37,14 +37,14 @@ import { createReducer, bindSelectors } from './util';
* @template {object} Selectors
* @template {object} RootSelectors
* @typedef Module
* @prop {(...args: any[]) => State} init -
* @prop {(...args: any[]) => State} initialState -
* Function that returns the initial state for the module
* @prop {string} namespace -
* The key under which this module's state will live in the store's root state
* @prop {Reducers<State>} update -
* @prop {Reducers<State>} reducers -
* Map of action types to "reducer" functions that process an action and return
* the changes to the state
* @prop {Actions} actions
* @prop {Actions} actionCreators
* Object containing action creator functions
* @prop {Selectors} selectors
* Object containing selector functions
......@@ -99,7 +99,7 @@ import { createReducer, bindSelectors } from './util';
* from that state.
*
* In addition to the standard Redux store interface, the returned store also exposes
* each action and selector from the input modules as a method. For example, if
* each action creator and selector from the input modules as a method. For example, if
* a store is created from a module that has a `getWidget(<id>)` selector and
* an `addWidget(<object>)` action, a consumer would use `store.getWidget(<id>)`
* to fetch an item and `store.addWidget(<object>)` to dispatch an action that
......@@ -112,7 +112,7 @@ import { createReducer, bindSelectors } from './util';
* what store state a component depends upon and re-render when it changes.
*
* @param {Module<any,any,any,any>[]} modules
* @param {any[]} [initArgs] - Arguments to pass to each state module's `init` function
* @param {any[]} [initArgs] - Arguments to pass to each state module's `initialState` function
* @param {any[]} [middleware] - List of additional Redux middlewares to use
* @return Store<any,any,any>
*/
......@@ -137,9 +137,9 @@ export function createStore(modules, initArgs = [], middleware = []) {
//
modules.forEach(module => {
if (module.namespace) {
initialState[module.namespace] = module.init(...initArgs);
initialState[module.namespace] = module.initialState(...initArgs);
allReducers[module.namespace] = createReducer(module.update);
allReducers[module.namespace] = createReducer(module.reducers);
allSelectors[module.namespace] = {
selectors: module.selectors,
rootSelectors: module.rootSelectors || {},
......@@ -172,7 +172,7 @@ export function createStore(modules, initArgs = [], middleware = []) {
const store = redux.createStore(reducer, initialState, enhancer);
// Add actions and selectors as methods to the store.
const actions = Object.assign({}, ...modules.map(m => m.actions));
const actions = Object.assign({}, ...modules.map(m => m.actionCreators));
const boundActions = redux.bindActionCreators(actions, store.dispatch);
const boundSelectors = bindSelectors(allSelectors, store.getState);
......
......@@ -6,7 +6,7 @@
import { actionTypes } from '../util';
import { storeModule } from '../create-store';
function init() {
function initialState() {
return {
/**
* Annotation `$tag`s that correspond to annotations with active API requests
......@@ -32,7 +32,7 @@ function init() {
};
}
const update = {
const reducers = {
API_REQUEST_STARTED(state) {
return {
...state,
......@@ -107,7 +107,7 @@ const update = {
},
};
const actions = actionTypes(update);
const actions = actionTypes(reducers);
/** Action Creators */
......@@ -189,11 +189,11 @@ function isSavingAnnotation(state, annotation) {
/** @typedef {import('../../../types/api').Annotation} Annotation */
export default storeModule({
init,
update,
initialState,
reducers,
namespace: 'activity',
actions: {
actionCreators: {
annotationFetchStarted,
annotationFetchFinished,
annotationSaveStarted,
......
......@@ -89,7 +89,7 @@ function initializeAnnotation(annotation, tag) {
});
}
function init() {
function initialState() {
return {
/** @type {Annotation[]} */
annotations: [],
......@@ -105,7 +105,7 @@ function init() {
};
}
const update = {
const reducers = {
ADD_ANNOTATIONS: function (state, action) {
const updatedIDs = {};
const updatedTags = {};
......@@ -232,7 +232,7 @@ const update = {
},
};
const actions = util.actionTypes(update);
const actions = util.actionTypes(reducers);
/* Action creators */
......@@ -555,10 +555,10 @@ function savedAnnotations(state) {
}
export default storeModule({
init: init,
initialState,
namespace: 'annotations',
update: update,
actions: {
reducers,
actionCreators: {
addAnnotations,
clearAnnotations,
focusAnnotations,
......
......@@ -16,7 +16,7 @@ import { storeModule } from '../create-store';
* `persistedDefaults` service.
*/
function init() {
function initialState() {
/**
* Note that the persisted presence of any of these defaults cannot be
* guaranteed, so consumers of said defaults should be prepared to handle
......@@ -29,13 +29,13 @@ function init() {
};
}
const update = {
const reducers = {
SET_DEFAULT: function (state, action) {
return { [action.defaultKey]: action.value };
},
};
const actions = util.actionTypes(update);
const actions = util.actionTypes(reducers);
function setDefault(defaultKey, value) {
return { type: actions.SET_DEFAULT, defaultKey: defaultKey, value: value };
......@@ -58,10 +58,10 @@ function getDefaults(state) {
}
export default storeModule({
init,
initialState,
namespace: 'defaults',
update,
actions: {
reducers,
actionCreators: {
setDefault,
},
selectors: {
......
......@@ -2,7 +2,7 @@ import * as util from '../util';
import { storeModule } from '../create-store';
function init(settings) {
function initialState(settings) {
return {
/**
* The ID of the direct-linked group.
......@@ -42,7 +42,7 @@ function init(settings) {
};
}
const update = {
const reducers = {
UPDATE_DIRECT_LINKED_GROUP_FETCH_FAILED(state, action) {
return {
directLinkedGroupFetchFailed: action.directLinkedGroupFetchFailed,
......@@ -73,7 +73,7 @@ const update = {
},
};
const actions = util.actionTypes(update);
const actions = util.actionTypes(reducers);
/**
* Set the direct linked group id.
......@@ -143,10 +143,10 @@ function directLinkedGroupFetchFailed(state) {
}
export default storeModule({
init,
initialState,
namespace: 'directLinked',
update,
actions: {
reducers,
actionCreators: {
setDirectLinkedGroupFetchFailed,
setDirectLinkedGroupId,
setDirectLinkedAnnotationId,
......
......@@ -11,7 +11,7 @@ import { storeModule } from '../create-store';
* existing annotations.
*/
function init() {
function initialState() {
return [];
}
......@@ -57,7 +57,7 @@ export class Draft {
/* Reducer */
const update = {
const reducers = {
DISCARD_ALL_DRAFTS: function () {
return [];
},
......@@ -77,7 +77,7 @@ const update = {
},
};
const actions = util.actionTypes(update);
const actions = util.actionTypes(reducers);
/* Actions */
......@@ -188,10 +188,10 @@ const unsavedAnnotations = createSelector(
);
export default storeModule({
init,
initialState,
namespace: 'drafts',
update,
actions: {
reducers,
actionCreators: {
createDraft,
deleteNewAndEmptyDrafts,
discardAllDrafts,
......
......@@ -56,7 +56,7 @@ import { storeModule } from '../create-store';
* @prop {string} displayName
*/
function init(settings) {
function initialState(settings) {
const focusConfig = settings.focus || {};
return {
/**
......@@ -105,7 +105,7 @@ function focusFiltersFromConfig(focusConfig) {
};
}
const update = {
const reducers = {
CHANGE_FOCUS_MODE_USER: function (state, action) {
if (isValidFocusConfig({ user: action.user })) {
return {
......@@ -152,7 +152,7 @@ const update = {
},
};
const actions = actionTypes(update);
const actions = actionTypes(reducers);
// Action creators
......@@ -286,10 +286,10 @@ function hasAppliedFilter(state) {
}
export default storeModule({
init,
initialState,
namespace: 'filters',
update,
actions: {
reducers,
actionCreators: {
changeFocusModeUser,
setFilter,
setFilterQuery,
......
......@@ -20,12 +20,12 @@ import { storeModule } from '../create-store';
* @prop {string} uri - Current primary URI of the document being displayed
*/
function init() {
function initialState() {
// The list of frames connected to the sidebar app
return [];
}
const update = {
const reducers = {
CONNECT_FRAME: function (state, action) {
return [...state, action.frame];
},
......@@ -49,7 +49,7 @@ const update = {
},
};
const actions = util.actionTypes(update);
const actions = util.actionTypes(reducers);
/**
* Add a frame to the list of frames currently connected to the sidebar app.
......@@ -156,11 +156,11 @@ const searchUris = createShallowEqualSelector(
);
export default storeModule({
init: init,
initialState,
namespace: 'frames',
update: update,
reducers,
actions: {
actionCreators: {
connectFrame,
destroyFrame,
updateFrameAnnotationFetchStatus,
......
......@@ -9,7 +9,7 @@ import session from './session';
* @typedef {import('../../../types/api').Group} Group
*/
function init() {
function initialState() {
return {
/**
* List of groups.
......@@ -25,7 +25,7 @@ function init() {
};
}
const update = {
const reducers = {
FOCUS_GROUP(state, action) {
const group = state.groups.find(g => g.id === action.id);
if (!group) {
......@@ -67,7 +67,7 @@ const update = {
},
};
const actions = util.actionTypes(update);
const actions = util.actionTypes(reducers);
function clearGroups() {
return {
......@@ -198,10 +198,10 @@ const getCurrentlyViewingGroups = createSelector(
);
export default storeModule({
init,
initialState,
namespace: 'groups',
update,
actions: {
reducers,
actionCreators: {
focusGroup,
loadGroups,
clearGroups,
......
......@@ -2,11 +2,11 @@ import { actionTypes } from '../util';
import { replaceURLParams } from '../../util/url';
import { storeModule } from '../create-store';
function init() {
function initialState() {
return null;
}
const update = {
const reducers = {
UPDATE_LINKS(state, action) {
return {
...action.links,
......@@ -14,7 +14,7 @@ const update = {
},
};
const actions = actionTypes(update);
const actions = actionTypes(reducers);
/**
* Update the link map
......@@ -54,10 +54,10 @@ function getLink(state, linkName, params = {}) {
}
export default storeModule({
init,
initialState,
namespace: 'links',
update,
actions: {
reducers,
actionCreators: {
updateLinks,
},
selectors: {
......
......@@ -16,7 +16,7 @@ import annotations from './annotations';
import groups from './groups';
import route from './route';
function init() {
function initialState() {
return {
// Map of ID -> updated annotation for updates that have been received over
// the WebSocket but not yet applied
......@@ -28,7 +28,7 @@ function init() {
};
}
const update = {
const reducers = {
RECEIVE_REAL_TIME_UPDATES(state, action) {
return {
pendingUpdates: { ...action.pendingUpdates },
......@@ -76,7 +76,7 @@ const update = {
},
};
const actions = actionTypes(update);
const actions = actionTypes(reducers);
/**
* Record pending updates representing changes on the server that the client
......@@ -184,10 +184,10 @@ function hasPendingDeletion(state, id) {
}
export default storeModule({
init,
initialState,
namespace: 'realTimeUpdates',
update,
actions: {
reducers,
actionCreators: {
receiveRealTimeUpdates,
clearPendingUpdates,
},
......
......@@ -2,7 +2,7 @@ import { actionTypes } from '../util';
import { storeModule } from '../create-store';
function init() {
function initialState() {
return {
/**
* The current route.
......@@ -21,18 +21,18 @@ function init() {
};
}
const update = {
const reducers = {
CHANGE_ROUTE(state, { name, params }) {
return { name, params };
},
};
const actions = actionTypes(update);
const actions = actionTypes(reducers);
/**
* Change the active route.
*
* @param {string} name - Name of the route to activate. See `init` for possible values
* @param {string} name - Name of the route to activate. See `initialState` for possible values
* @param {Object.<string,string>} params - Parameters associated with the route
*/
function changeRoute(name, params = {}) {
......@@ -59,10 +59,10 @@ function routeParams(state) {
}
export default storeModule({
init,
initialState,
namespace: 'route',
update,
actions: {
reducers,
actionCreators: {
changeRoute,
},
selectors: {
......
......@@ -44,7 +44,7 @@ function initialSelection(settings) {
return selection;
}
function init(settings) {
function initialState(settings) {
return {
/**
* The following objects map annotation identifiers to a boolean
......@@ -100,7 +100,7 @@ const resetSelection = () => {
};
};
const update = {
const reducers = {
CLEAR_SELECTION: function () {
return resetSelection();
},
......@@ -204,7 +204,7 @@ const update = {
},
};
const actions = util.actionTypes(update);
const actions = util.actionTypes(reducers);
/* Action Creators */
......@@ -388,11 +388,11 @@ const sortKeys = createSelector(
);
export default storeModule({
init: init,
initialState,
namespace: 'selection',
update: update,
reducers,
actions: {
actionCreators: {
clearSelection,
selectAnnotations,
selectTab,
......
......@@ -23,7 +23,7 @@ const initialProfile = {
userid: null,
};
function init(settings) {
function initialState(settings) {
return {
/**
* The app's default authority (user identity provider), from settings,
......@@ -41,7 +41,7 @@ function init(settings) {
};
}
const update = {
const reducers = {
UPDATE_PROFILE: function (state, action) {
return {
profile: { ...action.profile },
......@@ -49,7 +49,7 @@ const update = {
},
};
const actions = util.actionTypes(update);
const actions = util.actionTypes(reducers);
/**
* Update the profile information for the current user.
......@@ -111,11 +111,11 @@ function profile(state) {
}
export default storeModule({
init,
initialState,
namespace: 'session',
update,
reducers,
actions: {
actionCreators: {
updateProfile,
},
......
......@@ -16,7 +16,7 @@ import * as util from '../util';
import { storeModule } from '../create-store';
function init() {
function initialState() {
return {
/*
* The `panelName` of the currently-active sidebar panel.
......@@ -32,7 +32,7 @@ function init() {
};
}
const update = {
const reducers = {
OPEN_SIDEBAR_PANEL: function (state, action) {
return { activePanelName: action.panelName };
},
......@@ -76,7 +76,7 @@ const update = {
},
};
const actions = util.actionTypes(update);
const actions = util.actionTypes(reducers);
/**
* Designate `panelName` as the currently-active panel name
......@@ -124,10 +124,10 @@ function isSidebarPanelOpen(state, panelName) {
export default storeModule({
namespace: 'sidebarPanels',
init: init,
update: update,
initialState,
reducers,
actions: {
actionCreators: {
openSidebarPanel,
closeSidebarPanel,
toggleSidebarPanel,
......
......@@ -5,8 +5,8 @@ import realTimeUpdates from '../real-time-updates';
import { $imports } from '../real-time-updates';
import selection from '../selection';
const { removeAnnotations } = annotations.actions;
const { focusGroup } = groups.actions;
const { removeAnnotations } = annotations.actionCreators;
const { focusGroup } = groups.actionCreators;
describe('sidebar/store/modules/real-time-updates', () => {
let fakeAnnotationExists;
......
......@@ -12,7 +12,7 @@ describe('sidebar/store/modules/sidebar-panels', () => {
store = createStore([sidebarPanels]);
});
describe('#init', () => {
describe('#initialState', () => {
it('sets initial `activePanelName` to `null`', () => {
assert.equal(getSidebarPanelsState().activePanelName, null);
});
......
......@@ -16,13 +16,13 @@ import * as util from '../util';
* maintains state only; it's up to other layers to handle the management
* and interactions with these messages.
*/
function init() {
function initialState() {
return {
messages: [],
};
}
const update = {
const reducers = {
ADD_MESSAGE: function (state, action) {
return {
messages: state.messages.concat({ ...action.message }),
......@@ -47,7 +47,7 @@ const update = {
},
};
const actions = util.actionTypes(update);
const actions = util.actionTypes(reducers);
/** Actions */
......@@ -113,10 +113,10 @@ function hasMessage(state, type, text) {
}
export default storeModule({
init,
initialState,
namespace: 'toastMessages',
update,
actions: {
reducers,
actionCreators: {
addToastMessage: addMessage,
removeToastMessage: removeMessage,
updateToastMessage: updateMessage,
......
......@@ -7,7 +7,7 @@ import { storeModule } from '../create-store';
* sidebar.
*/
function init() {
function initialState() {
return {
// Has the sidebar ever been opened? NB: This is not necessarily the
// current state of the sidebar, but tracks whether it has ever been open
......@@ -16,7 +16,7 @@ function init() {
};
}
const update = {
const reducers = {
SET_HIGHLIGHTS_VISIBLE: function (state, action) {
return { visibleHighlights: action.visible };
},
......@@ -30,7 +30,7 @@ const update = {
},
};
const actions = util.actionTypes(update);
const actions = util.actionTypes(reducers);
// Action creators
......@@ -56,10 +56,10 @@ function hasSidebarOpened(state) {
}
export default storeModule({
init: init,
initialState,
namespace: 'viewer',
update: update,
actions: {
reducers,
actionCreators: {
setShowHighlights,
setSidebarOpened,
},
......
......@@ -7,12 +7,12 @@ const A = 0;
const modules = [
{
// namespaced module A
init(value = 0) {
initialState(value = 0) {
return { count: value };
},
namespace: 'a',
update: {
reducers: {
INCREMENT_COUNTER_A: (state, action) => {
return { count: state.count + action.amount };
},
......@@ -21,7 +21,7 @@ const modules = [
},
},
actions: {
actionCreators: {
incrementA(amount) {
return { type: 'INCREMENT_COUNTER_A', amount };
},
......@@ -41,12 +41,12 @@ const modules = [
},
{
// namespaced module B
init(value = 0) {
initialState(value = 0) {
return { count: value };
},
namespace: 'b',
update: {
reducers: {
INCREMENT_COUNTER_B: (state, action) => {
return { count: state.count + action.amount };
},
......@@ -55,7 +55,7 @@ const modules = [
},
},
actions: {
actionCreators: {
incrementB(amount) {
return { type: 'INCREMENT_COUNTER_B', amount };
},
......@@ -95,7 +95,7 @@ describe('createStore', () => {
assert.calledWith(subscriber);
});
it('passes initial state args to `init` function', () => {
it('passes initial state args to `initialState` function', () => {
const store = counterStore([21]);
assert.equal(store.getState().a.count, 21);
});
......@@ -108,20 +108,20 @@ describe('createStore', () => {
it('adds selectors as methods to the store', () => {
const store = counterStore();
store.dispatch(modules[A].actions.incrementA(5));
store.dispatch(modules[A].actionCreators.incrementA(5));
assert.equal(store.getCountA(), 5);
});
it('adds root selectors as methods to the store', () => {
const store = counterStore();
store.dispatch(modules[A].actions.incrementA(5));
store.dispatch(modules[A].actionCreators.incrementA(5));
assert.equal(store.getCountAFromRoot(), 5);
});
it('applies `thunk` middleware by default', () => {
const store = counterStore();
const doubleAction = (dispatch, getState) => {
dispatch(modules[A].actions.incrementA(getState().a.count));
dispatch(modules[A].actionCreators.incrementA(getState().a.count));
};
store.incrementA(5);
......
......@@ -8,11 +8,11 @@ import { useStoreProxy, $imports } from '../use-store';
const thingsModule = {
namespace: 'things',
init: () => ({
initialState: () => ({
things: [],
}),
update: {
reducers: {
ADD_THING(state, action) {
if (state.things.some(t => t.id === action.thing.id)) {
return {};
......@@ -21,7 +21,7 @@ const thingsModule = {
},
},
actions: {
actionCreators: {
addThing(id) {
return { type: 'ADD_THING', thing: { id } };
},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment