Easy-peasy: Select from the whole store

Created on 13 Jan 2019  路  13Comments  路  Source: ctrlplusb/easy-peasy

How to use select on the whole store state?

Most helpful comment

Hey @dioklecijan

Thanks for raising this! The way you laid out your problem has actually inspired me with an idea which could actually improve selectors in many ways, including allowing access to any part of the state. I don't want to make any promises or get your hopes up, but let me experiment a bit and I will get back to you soon. 馃憤

All 13 comments

I created two select functions to consume the store directly and inside React, but it lookes duplicated.

export const getForm = () => {
    return upperFirst(camelCase(store.getState().router.query.form))
}

export const useForm = () => {
    const form = useStore(state => state.router.query.form)
    return upperFirst(camelCase(form))
}

I came into this pattern:

// selectors and hooks file
import memoize from 'memoize-state'
export const getForm = () => memoize(state => upperFirst(camelCase(state.router.query.form)))

And use it like this:

// Not in the component
getForm()(state)
// In the component
const form = useState(getForm())

Now it is almost perfect, just to get rid of the (state)
I use the selector usually in the effect function.
I wish to mount the selector somewhere in the tree and it will receive the whole tree automatically as a state :)

I am now very excited about the lib, it works fluently! With Next.js using next-with-redux

1.1. I would like to do a selector like this:

selectX: params => store => store.x.y

1.2. It has automatic memoize . So it gets transformed into

memoize(params => memoize(store => store.x.y))

1.3. BTW Current select(state) - how it accepts parameter?

  1. Init to have a config to choose memoize lib.
    It is because I want to use memoize-state : it is intended for such case, it automatically detects which parts of the state being used.

Question: why didn't you choose the store tree to look like mobx-state-tree:
.view , .model sections. It would be authentic and better organized, don't you think? Maybe will refactor ?

There is also the recompose way:

Method: payload => state => { }

And the object way:

method({params, state})

I think the object way more natural, it is like props in react - props get injected the state or other parameters. What to you think?

@lishine Unrelated, but could you please format the code in your comments for easier reading ?

Thanks @revskill10
You mean like the above?
Or you mean about the first comment with the large indent ? (It is because of using tabs...)

In your case, there's a simple solution.
Just create a new root substree in your store, then use select from there (you can access the whole store inside root)

Closing this issue and believe it's resolved 馃憤

Hey @ctrlplusb - Being able to optionally pull in the whole store state in a thunk is great. (as per the docs and #101 )

Would it be possible to use the same API on a select? i.e. select( (state, { getStoreState }) => ...

I saw the note just above - but I'm not sure how 'adding a select on a new root subtree' actually solves the issue, since I imagine (in my case at least), I'd have to move a whole bunch of other things into the root as well to make that work...

At the moment, the solution I've come up with is to use a thunk which uses getStoreState to pull the state I want to use in my selector into the subtree and reference it as local state. But that's clearly ugly as hell.

Sorry if I'm missing something obvious.

ps. easy-peasy is awesome!

I do not see the solution either.
Assume following selector and model:

// depends on employees and roles
const empViewSelector = select(state => id => ({
    ...state.employees[id],
    roleName: state.roles[state.employees[id].roleId].name
  })
);

const model = {
  employees: [1: {roleId:1, name: 'John Doe'}],
  roles: [1: {name: 'admin'}],
  empView: empViewSelector,
  ...
  100 other objects
  ...  
}

Subtree as mentioned by @revskill10 is not the solution because
100 other objects want to access employees and roles too:

const model = {
  subtree: {
    employees, 
    roles, 
    empView
  },
  ...
  100 other objects (begging for employees and roles)
  ...    
}

So, the situation is that empView must be attached to the root state
and runs on every change in any of 102 objects.

I wish to reduce dependency to employees and roles. Something like:

const empViewSelector = select([state.employees, state.roles], 
  (employees, roles, id) => ({
    ...employees[id],
    roleName: roles[employees[id].roleId].name
  })
)

and possibly use empView in nested state:

const model ={
  employeesGrande: {
    employees, 
    empView: emptViewSelector,
  },  
  roles: [1: {name: 'admin'}],
  ...
  100 other objects
  ...  
}

How to achieve this?

PS. I discovered easy-peasy two days ago and it looks like the right way to do you know what. Really nice work @ctrlplusb!

Hey @dioklecijan

Thanks for raising this! The way you laid out your problem has actually inspired me with an idea which could actually improve selectors in many ways, including allowing access to any part of the state. I don't want to make any promises or get your hopes up, but let me experiment a bit and I will get back to you soon. 馃憤

Was this page helpful?
0 / 5 - 0 ratings

Related issues

coooolers picture coooolers  路  5Comments

lishine picture lishine  路  6Comments

24dev picture 24dev  路  5Comments

ifyoumakeit picture ifyoumakeit  路  5Comments

Windynik picture Windynik  路  5Comments