Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support groups of selectors #15

Open
anikolaev opened this issue Mar 25, 2019 · 3 comments
Open

Support groups of selectors #15

anikolaev opened this issue Mar 25, 2019 · 3 comments

Comments

@anikolaev
Copy link

I am creating a copy here as it needs to be fixed in both lib and extension.

There are 27 files in my selectors folder and they share selector names like id so it is always useless to see a flat structure. Here is the picture after registering only 4 of 27 files:

image

Here is a typical structure of my files containing selectors and how I register them. Maybe I am doing something wrong.

selectors/accessTokens.js

import { createSelector } from 'reselect'

import * as entities from './entities'

const ids = state => {
  return state.accessTokensList.get('accessTokenIds')
}

export const fetching = (state) => {
  return state.accessTokensList.get('fetching')
}

export const listEntities = createSelector(
  ids, entities.accessTokens,
  (ids, entities) => ids.map(id => entities.get(`${id}`))
)
...

selectors/entities.js

import { Map } from 'immutable'

export const ticketingSystems = state => state.entities.get('ticketingSystems') || Map()
export const tickets = state => state.entities.get('tickets') || Map()
export const ticketFieldValues = state => state.entities.get('ticketFieldValues') || Map()
...

selectors/audits.js

import { createSelector } from 'reselect'

import * as entities from './entities'

const ids = state => {
  return state.auditsList.get('auditIds')
}

export const fetching = (state) => {
  return state.auditsList.get('fetching')
}

export const listEntities = createSelector(
  ids, entities.audits,
  (ids, entities) => ids.map(id => entities.get(`${id}`))
)

export const selectedAuditId = (state) => {
  return state.auditsList.get('selectedAuditId') || null
}

export const selectedAudit = createSelector(
  selectedAuditId, entities.audits,
  (id, entities) => entities.get(`${id}`)
)
...

...

selectors/index.js

import * as accessTokens from './accessTokens'
import * as audits from './audits'
import * as ticketStatuses from './ticketStatuses'
import * as entities from './entities'

export {
  accessTokens,
  audits,
  ticketStatuses,
  entities
}

store.js

import { createStore, applyMiddleware, compose } from 'redux'
import { routerMiddleware } from 'connected-react-router'
import createSagaMiddleware from 'redux-saga'
import createRootReducer from 'reducers/rootReducer'
import { appHistory } from 'appHistory'
import root from 'sagas/root'

import * as selectors from 'selectors'
import * as ReselectTools from 'reselect-tools'

const connectedRootReducer = createRootReducer(appHistory)
const initialState = {}
const sagaMiddleware = createSagaMiddleware()

const middleware = [
  routerMiddleware(appHistory),
  sagaMiddleware
]

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const enhancer = composeEnhancers(
  applyMiddleware(...middleware)
)

const store = createStore(connectedRootReducer, initialState, enhancer)
sagaMiddleware.run(root)

ReselectTools.getStateWith(() => store.getState())
ReselectTools.registerSelectors(selectors.accessTokens)
ReselectTools.registerSelectors(selectors.audits)
ReselectTools.registerSelectors(selectors.ticketStatuses)
ReselectTools.registerSelectors(selectors.entities)

export { store }

I think there should be a way to add selectors specifying the name it their groups like 'audits', 'entities' etc. In the code they are imported as

import * as auditsSelector from 'selectors/audits'

so it will be clear for developers.

@skortchmark9
Copy link
Owner

Hey @anikolaev I think I have a solution for your problem!

The key here is that when you do
import * as auditsSelector you actually get an object, which looks like this:

console.log(auditsSelector);
// { 'selectedAudit': selectedAuditFunc }

Since this is just a plain javascript object, you can do namespacing pretty easily:

const namespaceSelectors = (selectors, prefix) => {
    const namespaced = {};
    Object.entries(selectors).forEach(([name, func]) => {
        namespaced[`${prefix}:${name}`] = func;
    });
    return namespaced;
};

Usage would be like so:

import * as auditsSelectors from 'selectors/audits'

ReselectTools.registerSelectors(
    namespaceSelectors(auditsSelectors, 'audits')
);

Try that out and let me know if it helps!

Thanks,
Sam

@anikolaev
Copy link
Author

anikolaev commented Mar 25, 2019

Yes, I thought about that but they would still be displayed as flat nodes in a single line as I showed in my screenshot. So I will have to move nodes every time to make them readable. And there are just 4 of 27 groups shown. It will be a mess with all selectors shown. So I think it is better to add support of this functionality to lib and extensions and visualize groups of selectors somehow.

@skortchmark9
Copy link
Owner

@anikolaev why do you think they would be displayed as flat nodes? Did you try it out?

From a cursory glance it looks like it ought to "just work" since the selectorNames are set on the function objects themselves.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants