Redux: Another implementation for Selector Pattern











up vote
1
down vote

favorite












The following example shows the usual implementation for the selector pattern. Then I'll discuss the problems of this implementation. After that I'll suggest another implementation that may prove useful.



Usual implementation:



Here is how the root reducer looks like along with public selectors:



// reducers/index.js
import { combineReducers } from 'redux';
import * as Items from './items';
import * as Login from './login';

export default combineReducers({
login: Login.reducer,
items: Items.reducer
// more slices ...
});


// PUBLIC SELECTORS
export const getToken = state => Login.getToken(state.login);
export const getLoginError = state => Login.getError(state.login);
export const isLoginLoading = state => Login.isLoading(state.login);

export const getItems = state => Items.getToken(state.items);
export const getCurrentItem = state => Items.getError(state.items);
export const isItemsLoading = state => Items.isLoading(state.items);

// Selectors for data from other slices
// ...

// Selectors for derived data from multiple slices
export const getOwnedItems = (state) => {
// ...
};


Here is how a slice reducer look like along with its private selectors:



// reducers/login.js
import {
// actions ...
} from '../actions';

const defaultState = {
// ...
};

export const reducer = (state = defaultState, action = {}) => {
// Reducer ...
};


// PRIVATE SELECTORS
export const getToken = state => state.token;
export const getError = state => state.error;
export const isLoading = state => state.loading;


Another slice reducer and its private selectors:



// reducers/items.js
import {
// actions ...
} from '../actions';

const defaultState = {
// ...
};

export const reducer = (state = defaultState, action = {}) => {
// Reducer ...
};


// PRIVATE SELECTORS
export const getItems = state => state.items;
export const getCurrentItem = state => state.currentItem;
export const isItemsLoading = state => state.isLoading;


The usage of this implementation would be like this:



import { getLoginError, isLoginLoading } from '../reducers';

const mapStateToProps = state => {
return {
error: getLoginError(state),
loading: isLoginLoading(state)
};
};


The Problem:



The previous implementation of selectors requires all public selectors to be defined in reducers/index.js. Notice that public selectors receives the full state which is managed by the root reducer defined in reducers/index.js.



Public selectors can be divided into two types. Extraction selectors just for extracting data from the state. And Derived information Selectors which computes derived information from the state. For the users all selectors are the same and their purpose is to separate the client code from the shape of the state.



First problem with the previous implementation is that all extraction selectors are written twice. Once as a public selector and another as a private selector where the public selector is calling the private one.



Second problem is that all private selectors for specific slice can only receive that slice but it is passed many times, once for each usage instance of a private selector for that slice which seems a good case for refactoring.



The following is another implementation for selectors that could prove useful:



Another implementation



The root reducer file will only provide one select() function which takes the full state and provide the public interface from which client code can retrieve data from the state.



The interface may consist of functions or collections of functions grouped under a name.
This structure allow us to provide an interface that will make implementing extraction selectors trivial in addition to the ability to provide more customized public selectors.



Please don't confuse the structure of the selector with the shape of the state. There is not coupling between the two. The public selector can still implement the same interface for the application even if the shape of the state changed.



Here is the public selectors implemented in select(state) function:



// reducers/index.js
import { combineReducers } from 'redux';
import * as Items from './items';
import * as Login from './login';

export default combineReducers({
login: Login.reducer,
items: Items.reducer
// more slices ...
});


// PUBLIC SELECTORS
export const select = (state) => {
return {
login: Login.select(state.login),
items: Items.select(state.items),

// Selectors for drived data from multiple slices
getOwnedItems: () => {
// ...
}
};
};


Here is private selectors inplemented in the same way:



// reducers/login.js
import {
// actions ...
} from '../actions';

const defaultState = {
// ...
};

export const reducer = (state = defaultState, action = {}) => {
// Reducer ...
};


// PRIVATE SELECTORS
export const select = (state) => {
return {
getToken: () => state.token,
getError: () => state.error,
isLoading: () => state.loading
};
};


Again for another slice:



// reducers/items.js
import {
// actions ...
} from '../actions';

const defaultState = {
// ...
};

export const reducer = (state = defaultState, action = {}) => {
// Reducer ...
};


// PRIVATE SELECTORS
export const select = (state) => {
return {
getItems: () => state.items,
getCurrentItem: () => state.currentItem,
isLoading: () => state.loading
};
};


The usage of this implementation looks like this:



import { select } from '../reducers';

const mapStateToProps = state => {
return {
error: select(state).login.getError(),
loading: select(state).login.isLoading()
};
};


Question 1:



What are the drawbacks of this implementation?



Question 2:



Is there another way to address the problems described above?



Thank you










share|improve this question


























    up vote
    1
    down vote

    favorite












    The following example shows the usual implementation for the selector pattern. Then I'll discuss the problems of this implementation. After that I'll suggest another implementation that may prove useful.



    Usual implementation:



    Here is how the root reducer looks like along with public selectors:



    // reducers/index.js
    import { combineReducers } from 'redux';
    import * as Items from './items';
    import * as Login from './login';

    export default combineReducers({
    login: Login.reducer,
    items: Items.reducer
    // more slices ...
    });


    // PUBLIC SELECTORS
    export const getToken = state => Login.getToken(state.login);
    export const getLoginError = state => Login.getError(state.login);
    export const isLoginLoading = state => Login.isLoading(state.login);

    export const getItems = state => Items.getToken(state.items);
    export const getCurrentItem = state => Items.getError(state.items);
    export const isItemsLoading = state => Items.isLoading(state.items);

    // Selectors for data from other slices
    // ...

    // Selectors for derived data from multiple slices
    export const getOwnedItems = (state) => {
    // ...
    };


    Here is how a slice reducer look like along with its private selectors:



    // reducers/login.js
    import {
    // actions ...
    } from '../actions';

    const defaultState = {
    // ...
    };

    export const reducer = (state = defaultState, action = {}) => {
    // Reducer ...
    };


    // PRIVATE SELECTORS
    export const getToken = state => state.token;
    export const getError = state => state.error;
    export const isLoading = state => state.loading;


    Another slice reducer and its private selectors:



    // reducers/items.js
    import {
    // actions ...
    } from '../actions';

    const defaultState = {
    // ...
    };

    export const reducer = (state = defaultState, action = {}) => {
    // Reducer ...
    };


    // PRIVATE SELECTORS
    export const getItems = state => state.items;
    export const getCurrentItem = state => state.currentItem;
    export const isItemsLoading = state => state.isLoading;


    The usage of this implementation would be like this:



    import { getLoginError, isLoginLoading } from '../reducers';

    const mapStateToProps = state => {
    return {
    error: getLoginError(state),
    loading: isLoginLoading(state)
    };
    };


    The Problem:



    The previous implementation of selectors requires all public selectors to be defined in reducers/index.js. Notice that public selectors receives the full state which is managed by the root reducer defined in reducers/index.js.



    Public selectors can be divided into two types. Extraction selectors just for extracting data from the state. And Derived information Selectors which computes derived information from the state. For the users all selectors are the same and their purpose is to separate the client code from the shape of the state.



    First problem with the previous implementation is that all extraction selectors are written twice. Once as a public selector and another as a private selector where the public selector is calling the private one.



    Second problem is that all private selectors for specific slice can only receive that slice but it is passed many times, once for each usage instance of a private selector for that slice which seems a good case for refactoring.



    The following is another implementation for selectors that could prove useful:



    Another implementation



    The root reducer file will only provide one select() function which takes the full state and provide the public interface from which client code can retrieve data from the state.



    The interface may consist of functions or collections of functions grouped under a name.
    This structure allow us to provide an interface that will make implementing extraction selectors trivial in addition to the ability to provide more customized public selectors.



    Please don't confuse the structure of the selector with the shape of the state. There is not coupling between the two. The public selector can still implement the same interface for the application even if the shape of the state changed.



    Here is the public selectors implemented in select(state) function:



    // reducers/index.js
    import { combineReducers } from 'redux';
    import * as Items from './items';
    import * as Login from './login';

    export default combineReducers({
    login: Login.reducer,
    items: Items.reducer
    // more slices ...
    });


    // PUBLIC SELECTORS
    export const select = (state) => {
    return {
    login: Login.select(state.login),
    items: Items.select(state.items),

    // Selectors for drived data from multiple slices
    getOwnedItems: () => {
    // ...
    }
    };
    };


    Here is private selectors inplemented in the same way:



    // reducers/login.js
    import {
    // actions ...
    } from '../actions';

    const defaultState = {
    // ...
    };

    export const reducer = (state = defaultState, action = {}) => {
    // Reducer ...
    };


    // PRIVATE SELECTORS
    export const select = (state) => {
    return {
    getToken: () => state.token,
    getError: () => state.error,
    isLoading: () => state.loading
    };
    };


    Again for another slice:



    // reducers/items.js
    import {
    // actions ...
    } from '../actions';

    const defaultState = {
    // ...
    };

    export const reducer = (state = defaultState, action = {}) => {
    // Reducer ...
    };


    // PRIVATE SELECTORS
    export const select = (state) => {
    return {
    getItems: () => state.items,
    getCurrentItem: () => state.currentItem,
    isLoading: () => state.loading
    };
    };


    The usage of this implementation looks like this:



    import { select } from '../reducers';

    const mapStateToProps = state => {
    return {
    error: select(state).login.getError(),
    loading: select(state).login.isLoading()
    };
    };


    Question 1:



    What are the drawbacks of this implementation?



    Question 2:



    Is there another way to address the problems described above?



    Thank you










    share|improve this question
























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      The following example shows the usual implementation for the selector pattern. Then I'll discuss the problems of this implementation. After that I'll suggest another implementation that may prove useful.



      Usual implementation:



      Here is how the root reducer looks like along with public selectors:



      // reducers/index.js
      import { combineReducers } from 'redux';
      import * as Items from './items';
      import * as Login from './login';

      export default combineReducers({
      login: Login.reducer,
      items: Items.reducer
      // more slices ...
      });


      // PUBLIC SELECTORS
      export const getToken = state => Login.getToken(state.login);
      export const getLoginError = state => Login.getError(state.login);
      export const isLoginLoading = state => Login.isLoading(state.login);

      export const getItems = state => Items.getToken(state.items);
      export const getCurrentItem = state => Items.getError(state.items);
      export const isItemsLoading = state => Items.isLoading(state.items);

      // Selectors for data from other slices
      // ...

      // Selectors for derived data from multiple slices
      export const getOwnedItems = (state) => {
      // ...
      };


      Here is how a slice reducer look like along with its private selectors:



      // reducers/login.js
      import {
      // actions ...
      } from '../actions';

      const defaultState = {
      // ...
      };

      export const reducer = (state = defaultState, action = {}) => {
      // Reducer ...
      };


      // PRIVATE SELECTORS
      export const getToken = state => state.token;
      export const getError = state => state.error;
      export const isLoading = state => state.loading;


      Another slice reducer and its private selectors:



      // reducers/items.js
      import {
      // actions ...
      } from '../actions';

      const defaultState = {
      // ...
      };

      export const reducer = (state = defaultState, action = {}) => {
      // Reducer ...
      };


      // PRIVATE SELECTORS
      export const getItems = state => state.items;
      export const getCurrentItem = state => state.currentItem;
      export const isItemsLoading = state => state.isLoading;


      The usage of this implementation would be like this:



      import { getLoginError, isLoginLoading } from '../reducers';

      const mapStateToProps = state => {
      return {
      error: getLoginError(state),
      loading: isLoginLoading(state)
      };
      };


      The Problem:



      The previous implementation of selectors requires all public selectors to be defined in reducers/index.js. Notice that public selectors receives the full state which is managed by the root reducer defined in reducers/index.js.



      Public selectors can be divided into two types. Extraction selectors just for extracting data from the state. And Derived information Selectors which computes derived information from the state. For the users all selectors are the same and their purpose is to separate the client code from the shape of the state.



      First problem with the previous implementation is that all extraction selectors are written twice. Once as a public selector and another as a private selector where the public selector is calling the private one.



      Second problem is that all private selectors for specific slice can only receive that slice but it is passed many times, once for each usage instance of a private selector for that slice which seems a good case for refactoring.



      The following is another implementation for selectors that could prove useful:



      Another implementation



      The root reducer file will only provide one select() function which takes the full state and provide the public interface from which client code can retrieve data from the state.



      The interface may consist of functions or collections of functions grouped under a name.
      This structure allow us to provide an interface that will make implementing extraction selectors trivial in addition to the ability to provide more customized public selectors.



      Please don't confuse the structure of the selector with the shape of the state. There is not coupling between the two. The public selector can still implement the same interface for the application even if the shape of the state changed.



      Here is the public selectors implemented in select(state) function:



      // reducers/index.js
      import { combineReducers } from 'redux';
      import * as Items from './items';
      import * as Login from './login';

      export default combineReducers({
      login: Login.reducer,
      items: Items.reducer
      // more slices ...
      });


      // PUBLIC SELECTORS
      export const select = (state) => {
      return {
      login: Login.select(state.login),
      items: Items.select(state.items),

      // Selectors for drived data from multiple slices
      getOwnedItems: () => {
      // ...
      }
      };
      };


      Here is private selectors inplemented in the same way:



      // reducers/login.js
      import {
      // actions ...
      } from '../actions';

      const defaultState = {
      // ...
      };

      export const reducer = (state = defaultState, action = {}) => {
      // Reducer ...
      };


      // PRIVATE SELECTORS
      export const select = (state) => {
      return {
      getToken: () => state.token,
      getError: () => state.error,
      isLoading: () => state.loading
      };
      };


      Again for another slice:



      // reducers/items.js
      import {
      // actions ...
      } from '../actions';

      const defaultState = {
      // ...
      };

      export const reducer = (state = defaultState, action = {}) => {
      // Reducer ...
      };


      // PRIVATE SELECTORS
      export const select = (state) => {
      return {
      getItems: () => state.items,
      getCurrentItem: () => state.currentItem,
      isLoading: () => state.loading
      };
      };


      The usage of this implementation looks like this:



      import { select } from '../reducers';

      const mapStateToProps = state => {
      return {
      error: select(state).login.getError(),
      loading: select(state).login.isLoading()
      };
      };


      Question 1:



      What are the drawbacks of this implementation?



      Question 2:



      Is there another way to address the problems described above?



      Thank you










      share|improve this question













      The following example shows the usual implementation for the selector pattern. Then I'll discuss the problems of this implementation. After that I'll suggest another implementation that may prove useful.



      Usual implementation:



      Here is how the root reducer looks like along with public selectors:



      // reducers/index.js
      import { combineReducers } from 'redux';
      import * as Items from './items';
      import * as Login from './login';

      export default combineReducers({
      login: Login.reducer,
      items: Items.reducer
      // more slices ...
      });


      // PUBLIC SELECTORS
      export const getToken = state => Login.getToken(state.login);
      export const getLoginError = state => Login.getError(state.login);
      export const isLoginLoading = state => Login.isLoading(state.login);

      export const getItems = state => Items.getToken(state.items);
      export const getCurrentItem = state => Items.getError(state.items);
      export const isItemsLoading = state => Items.isLoading(state.items);

      // Selectors for data from other slices
      // ...

      // Selectors for derived data from multiple slices
      export const getOwnedItems = (state) => {
      // ...
      };


      Here is how a slice reducer look like along with its private selectors:



      // reducers/login.js
      import {
      // actions ...
      } from '../actions';

      const defaultState = {
      // ...
      };

      export const reducer = (state = defaultState, action = {}) => {
      // Reducer ...
      };


      // PRIVATE SELECTORS
      export const getToken = state => state.token;
      export const getError = state => state.error;
      export const isLoading = state => state.loading;


      Another slice reducer and its private selectors:



      // reducers/items.js
      import {
      // actions ...
      } from '../actions';

      const defaultState = {
      // ...
      };

      export const reducer = (state = defaultState, action = {}) => {
      // Reducer ...
      };


      // PRIVATE SELECTORS
      export const getItems = state => state.items;
      export const getCurrentItem = state => state.currentItem;
      export const isItemsLoading = state => state.isLoading;


      The usage of this implementation would be like this:



      import { getLoginError, isLoginLoading } from '../reducers';

      const mapStateToProps = state => {
      return {
      error: getLoginError(state),
      loading: isLoginLoading(state)
      };
      };


      The Problem:



      The previous implementation of selectors requires all public selectors to be defined in reducers/index.js. Notice that public selectors receives the full state which is managed by the root reducer defined in reducers/index.js.



      Public selectors can be divided into two types. Extraction selectors just for extracting data from the state. And Derived information Selectors which computes derived information from the state. For the users all selectors are the same and their purpose is to separate the client code from the shape of the state.



      First problem with the previous implementation is that all extraction selectors are written twice. Once as a public selector and another as a private selector where the public selector is calling the private one.



      Second problem is that all private selectors for specific slice can only receive that slice but it is passed many times, once for each usage instance of a private selector for that slice which seems a good case for refactoring.



      The following is another implementation for selectors that could prove useful:



      Another implementation



      The root reducer file will only provide one select() function which takes the full state and provide the public interface from which client code can retrieve data from the state.



      The interface may consist of functions or collections of functions grouped under a name.
      This structure allow us to provide an interface that will make implementing extraction selectors trivial in addition to the ability to provide more customized public selectors.



      Please don't confuse the structure of the selector with the shape of the state. There is not coupling between the two. The public selector can still implement the same interface for the application even if the shape of the state changed.



      Here is the public selectors implemented in select(state) function:



      // reducers/index.js
      import { combineReducers } from 'redux';
      import * as Items from './items';
      import * as Login from './login';

      export default combineReducers({
      login: Login.reducer,
      items: Items.reducer
      // more slices ...
      });


      // PUBLIC SELECTORS
      export const select = (state) => {
      return {
      login: Login.select(state.login),
      items: Items.select(state.items),

      // Selectors for drived data from multiple slices
      getOwnedItems: () => {
      // ...
      }
      };
      };


      Here is private selectors inplemented in the same way:



      // reducers/login.js
      import {
      // actions ...
      } from '../actions';

      const defaultState = {
      // ...
      };

      export const reducer = (state = defaultState, action = {}) => {
      // Reducer ...
      };


      // PRIVATE SELECTORS
      export const select = (state) => {
      return {
      getToken: () => state.token,
      getError: () => state.error,
      isLoading: () => state.loading
      };
      };


      Again for another slice:



      // reducers/items.js
      import {
      // actions ...
      } from '../actions';

      const defaultState = {
      // ...
      };

      export const reducer = (state = defaultState, action = {}) => {
      // Reducer ...
      };


      // PRIVATE SELECTORS
      export const select = (state) => {
      return {
      getItems: () => state.items,
      getCurrentItem: () => state.currentItem,
      isLoading: () => state.loading
      };
      };


      The usage of this implementation looks like this:



      import { select } from '../reducers';

      const mapStateToProps = state => {
      return {
      error: select(state).login.getError(),
      loading: select(state).login.isLoading()
      };
      };


      Question 1:



      What are the drawbacks of this implementation?



      Question 2:



      Is there another way to address the problems described above?



      Thank you







      javascript redux react-redux






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked yesterday









      Meena Alfons

      5131625




      5131625





























          active

          oldest

          votes











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53265572%2fredux-another-implementation-for-selector-pattern%23new-answer', 'question_page');
          }
          );

          Post as a guest





































          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53265572%2fredux-another-implementation-for-selector-pattern%23new-answer', 'question_page');
          }
          );

          Post as a guest




















































































          Popular posts from this blog

          How to change which sound is reproduced for terminal bell?

          Can I use Tabulator js library in my java Spring + Thymeleaf project?

          Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents