Blog>
Snippets

Integrating middleware with Object.create(null) state objects

How to ensure Redux middleware handles state objects created with Object.create(null) without prototype.
function createStore(reducer, initialState) {
  let state = initialState || Object.create(null);
  let listeners = [];

  const getState = () => state;

  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach(listener => listener());
  };

  const subscribe = (listener) => {
    listeners.push(listener);
    return () => {
      listeners = listeners.filter(l => l !== listener);
    };
  };

  dispatch({}); // dummy dispatch to populate initialState

  return { getState, dispatch, subscribe };
}
A simplified 'createStore' function that initializes the state with 'Object.create(null)' if no initialState is provided. Includes methods to get the state, dispatch actions, and subscribe to changes.
function loggerMiddleware(store) {
  return function(next) {
    return function(action) {
      console.log('dispatching', action);
      let result = next(action);
      console.log('next state', store.getState());
      return result;
    };
  };
}
A 'loggerMiddleware' function that logs actions and states to the console. It demonstrates how middleware can seamlessly integrate with a store that uses state objects created with 'Object.create(null)'.
function applyMiddleware(store, middlewares) {
  middlewares = middlewares.slice();
  middlewares.reverse();

  let dispatch = store.dispatch;
  middlewares.forEach(middleware => {
    dispatch = middleware(store)(dispatch);
  });

  return Object.assign({}, store, { dispatch });
}
An 'applyMiddleware' function that enhances the store with middleware capabilities. Middlewares are applied in reverse order to compose the dispatch function.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Middleware Integration Example</title>
  <script src="store.js"></script>
  <script src="middlewares.js"></script>
</head>
<body>
  <!-- The rest of your application -->
  <script>
    const initialState = Object.create(null);
    initialState.count = 0;
    const store = createStore(reducer, initialState);
    const storeWithMiddleware = applyMiddleware(store, [loggerMiddleware]);

    // Test dispatch with middleware
    storeWithMiddleware.dispatch({ type: 'INCREMENT' });
  </script>
</body>
</html>
An HTML structure that includes the necessary scripts for the store and middlewares, initializes the store with an `Object.create(null)` state, and applies the middleware. It includes a test dispatch to show how actions are handled.
function reducer(state, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    default:
      return state;
  }
}
A simple reducer function that responds to an 'INCREMENT' action by increasing the 'count' property on the state. Uses the spread operator to ensure the state is copied without prototypes when updated.