Skip to content

Commit

Permalink
Add JSDoc annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
gaearon committed Jul 22, 2015
1 parent 27752e6 commit fffbe31
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 13 deletions.
2 changes: 2 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"node": true
},
"rules": {
"valid-jsdoc": 2,

"react/jsx-uses-react": 2,
"react/jsx-uses-vars": 2,
"react/react-in-jsx-scope": 2,
Expand Down
80 changes: 77 additions & 3 deletions src/createStore.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
import invariant from 'invariant';
import isPlainObject from './utils/isPlainObject';

// Don't ever try to handle these action types in your code. They are private.
// For any unknown actions, you must return the current state.
// If the current state is undefined, you must return the initial state.
/**
* These are private action types reserved by Redux.
* For any unknown actions, you must return the current state.
* If the current state is undefined, you must return the initial state.
* Do not reference these action types directly in your code.
*/
export var ActionTypes = {
INIT: '@@redux/INIT'
};

/**
* Creates a Redux store that holds the state tree.
* The only way to change the data in the store is to call `dispatch()` on it.
*
* There should only be a single store in your app. To specify how different
* parts of the state tree respond to actions, you may combine several reducers
* into a single reducer function by using `combineReducers`.
*
* @param {Function} reducer A function that returns the next state tree, given
* the current state tree and the action to handle.
*
* @param {any} initialState The initial state. You may optionally specify it
* to hydrate the state from the server in universal apps, or to restore a
* previously serialized user session.
*
* @returns {Store} A Redux store that lets you read the state, dispatch actions
* and subscribe to changes.
*/
export default function createStore(reducer, initialState) {
invariant(
typeof reducer === 'function',
Expand All @@ -18,10 +39,23 @@ export default function createStore(reducer, initialState) {
var currentState = initialState;
var listeners = [];

/**
* Reads the state tree managed by the store.
*
* @returns {any} The current state tree of your application.
*/
function getState() {
return currentState;
}

/**
* Adds a change listener. It will be called any time an action is dispatched,
* and some part of the state tree may potentially have changed. You may then
* call `getState()` to read the current state tree inside the callback.
*
* @param {Function} listener A callback to be invoked on every dispatch.
* @returns {Function} A function to remove this change listener.
*/
function subscribe(listener) {
listeners.push(listener);

Expand All @@ -31,6 +65,28 @@ export default function createStore(reducer, initialState) {
};
}

/**
* Dispatches an action. It is the only way to trigger a state change.
*
* The `reducer` function the store was created with will be called with the
* current state tree and the and the given `action`. Its return value will
* be considered the next state of the tree, and the change listeners will be
* notified.
*
* The base implementation only supports plain object actions. If you want to
* dispatch a promise, an observable, a thunk, or something else, you need to
* wrap your store creating function into the corresponding middleware. For
* example, see the documentation for the `redux-thunk` package. Even the
* middleware will eventually dispatch plain object actions using this method.
*
* @param {Object} action A plain object representing “what changed”. It is
* a good idea to keep actions serializable so you can record and replay user
* sessions, or use the time travelling Redux developer tools.
*
* @returns {Object} For convenience, the same action object you dispatched.
* Note that, if you use a custom middleware, it may wrap `dispatch()` to
* return something else (for example, a Promise you can await).
*/
function dispatch(action) {
invariant(
isPlainObject(action),
Expand All @@ -42,10 +98,28 @@ export default function createStore(reducer, initialState) {
return action;
}

/**
* Returns the reducer currently used by the store to calculate the state.
*
* It is likely that you will only need this function if you implement a hot
* reloading mechanism for Redux.
*
* @returns {Function} The reducer used by the current store.
*/
function getReducer() {
return currentReducer;
}

/**
* Replaces the reducer currently used by the store to calculate the state.
*
* You might need this if your app implements code splitting and you want to
* load some of the reducers dynamically. You might also need this if you
* implement a hot reloading mechanism for Redux.
*
* @param {Function} nextReducer The reducer for the store to use instead.
* @returns {void}
*/
function replaceReducer(nextReducer) {
currentReducer = nextReducer;
dispatch({ type: ActionTypes.INIT });
Expand Down
6 changes: 3 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import createStore from './createStore';
import compose from './utils/compose';
import combineReducers from './utils/combineReducers';
import bindActionCreators from './utils/bindActionCreators';
import applyMiddleware from './utils/applyMiddleware';
import compose from './utils/compose';

export {
createStore,
compose,
combineReducers,
bindActionCreators,
applyMiddleware
applyMiddleware,
compose
};
12 changes: 9 additions & 3 deletions src/utils/applyMiddleware.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import compose from './compose';

/**
* Creates a higher-order store that applies middleware to a store's dispatch.
* Creates a higher-order store that applies middleware to the dispatch method
* of the Redux store. This is handy for a variety of tasks, such as expressing
* asynchronous actions in a concise manner, or logging every action payload.
*
* See `redux-thunk` package as an example of the Redux middleware.
*
* Because middleware is potentially asynchronous, this should be the first
* higher-order store in the composition chain.
* @param {...Function} ...middlewares
* @return {Function} A higher-order store
*
* @param {...Function} middlewares The middleware chain to be applied.
* @return {Function} A higher-order store.
*/
export default function applyMiddleware(...middlewares) {
return (next) => (reducer, initialState) => {
Expand Down
15 changes: 15 additions & 0 deletions src/utils/bindActionCreators.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import mapValues from '../utils/mapValues';

/**
* Turns an object whose values are action creators, into an object with the
* same keys, but with every function wrapped into a `dispatch` call so they
* may be invoked directly. This is just a convenience method, as you can call
* `store.dispatch(MyActionCreators.doSomething())` yourself just fine.
*
* @param {Object} actionCreators An object whose values are action creator
* functions. One handy way to obtain it is to use ES6 `import * as` syntax.
*
* @param {Function} dispatch The `dispatch` function available on your Redux
* store.
*
* @returns {Object} The object mimicking the original object, but with every
* action creator wrapped into the `dispatch` call.
*/
export default function bindActionCreators(actionCreators, dispatch) {
return mapValues(actionCreators, actionCreator =>
(...args) => dispatch(actionCreator(...args))
Expand Down
18 changes: 17 additions & 1 deletion src/utils/combineReducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@ function getErrorMessage(key, action) {
);
}

/**
* Turns an object whose values are different reducer functions, into a single
* reducer function. It will call every child reducer, and gather their results
* into a single state object, whose keys correspond to the keys of the passed
* reducer functions.
*
* @param {Object} reducers An object whose values correspond to different
* reducer functions that need to be combined into one. One handy way to obtain
* it is to use ES6 `import * as reducers` syntax. The reducers may never return
* undefined for any action. Instead, they should return their initial state
* if the state passed to them was undefined, and the current state for any
* unrecognized action.
*
* @returns {Function} A reducer function that invokes every reducer inside the
* passed object, and builds a state object with the same shape.
*/
export default function combineReducers(reducers) {
var finalReducers = pick(reducers, (val) => typeof val === 'function');

Expand All @@ -38,7 +54,7 @@ export default function combineReducers(reducers) {
);
});

return function composition(state = {}, action) {
return function combination(state = {}, action) {
return mapValues(finalReducers, (reducer, key) => {
var newState = reducer(state[key], action);
invariant(
Expand Down
9 changes: 6 additions & 3 deletions src/utils/compose.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
/**
* Composes functions from left to right
* @param {...Function} funcs - Functions to compose
* @return {Function}
* Composes functions from left to right.
*
* @param {...Function} funcs - The functions to compose.
* @return {Function} A function that passes its only argument to the first of
* the `funcs`, then pipes its return value to the second one, and so on, until
* the last of the `funcs` is called, and its result is returned.
*/
export default function compose(...funcs) {
return funcs.reduceRight((composed, f) => f(composed));
Expand Down
4 changes: 4 additions & 0 deletions src/utils/isPlainObject.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
* @param {any} obj The object to inspect.
* @returns {boolean} True if the argument appears to be a plain object.
*/
export default function isPlainObject(obj) {
if (!obj) {
return false;
Expand Down
7 changes: 7 additions & 0 deletions src/utils/mapValues.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* Applies a function to every key-value pair inside an object.
*
* @param {Object} obj The source object.
* @param {Function} fn The mapper function taht receives the value and the key.
* @returns {Object} A new object that contains the mapped values for the keys.
*/
export default function mapValues(obj, fn) {
return Object.keys(obj).reduce((result, key) => {
result[key] = fn(obj[key], key);
Expand Down
7 changes: 7 additions & 0 deletions src/utils/pick.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* Picks key-value pairs from an object where values satisfy a predicate.
*
* @param {Object} obj The object to pick from.
* @param {Function} fn The predicate the values must satisfy to be copied.
* @returns {Object} The object with the values that satisfied the predicate.
*/
export default function pick(obj, fn) {
return Object.keys(obj).reduce((result, key) => {
if (fn(obj[key])) {
Expand Down

0 comments on commit fffbe31

Please sign in to comment.