Skip to content

Add reselect and redux actions to organizations #269

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

Merged
merged 10 commits into from
Aug 21, 2017
Merged

Conversation

alejandronanez
Copy link
Member

@alejandronanez alejandronanez commented Aug 19, 2017

Hey there!
I have a WIP branch with some updates on our codebase, it is still not done but I want to get early feedback on what I have here.

Will update this description as I make more progress - thanks for your patience!

Update

I completed my work on this but I decided to not include Immutable (not in this PR at least), because reselect + redux actions can live without Immutable.

So, the structure of the code has changed slightly, it goes like:

  1. We have a organization.selectors.js file. Here we're using reselect https://github.com/reactjs/reselect to "query" our store and get the data we need (reselect also has a bunch of benefits that you can read in their docs). This will save us some duplication when we want to get data from the store in different containers (we should reuse the selectors we have in the selectors file whenever we want to use an specific part of the state)
  2. We have a organization.constants.js file, I took this approach because we can use the constants through our reducers and actions (and in our tests in the future) also, I find the *.type.js notation quite ambiguous
  3. We no longer have that nasty switch statement in our reducer (I love this part)
  4. We have individual actions that take care of specific parts of the state, for example we can call an action just to update the loading state of the organization repos or update the error state only on the organization members - No more "batch" updates to the store (What I mean by that is having actions that takes care of 2+ things in our store) This will give us way more control over how our store is being updated.

import { createSelector } from 'reselect';
import { getOrganization as getOrganizationFromStore } from '../../root.reducer';

export const getOrganization = createSelector(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benefits of using reselect instead of querying the store by.doing.something.like.this

Selectors can compute derived data, allowing Redux to store the minimal possible state.
Selectors are efficient. A selector is not recomputed unless one of its arguments change.
Selectors are composable. They can be used as input to other selectors.

More info https://github.com/reactjs/reselect

getOrganizationIsPendingMembers,
} from '../index';

const selectors = createStructuredSelector({
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be almost the same as mapStateToProps but it uses reselect.

@@ -1,5 +0,0 @@
import { createActionSet } from 'utils';

export const GET_ORG = createActionSet('GET_ORG');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got rid of this *.type.js file in favor of *.constants.js and *.actions.js files

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice this is perfect, using redux-actions looks like we don't need a helper utility like createActionSet whatsoever

};

export const organizationReducer = (state = initialState, action = {}) => {
switch (action.type) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got rid of this ugly switch statement.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OMG how have I not used redux-actions before, it looks so much cleaner 😍

@@ -7,63 +19,65 @@ const initialState = {
isPendingOrg: false,
isPendingRepos: false,
isPendingMembers: false,
error: '',
organizationError: '',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created one error for organization, another for repositories and another for members.

@@ -0,0 +1,3 @@
import { Record } from 'immutable';

// WIP
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Immutable work should go here =)


dispatch({ type: GET_ORG.PENDING });
export const getOrg = createAction(GET_ORG);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating actions by using redux-actions I think this is more organized than have a manual dispatch with some boilerplate like {type: ... , payload: ...}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice agreed, makes things look so much more oganized 👍

root.reducer.js Outdated
@@ -16,3 +16,7 @@ export const rootReducer = combineReducers({
search: searchReducer,
notifications: notificationsReducer,
});

// Used to get organization information in selectors
export const getOrganization = state => state.organization;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used in the selectors to get some data.

@andrewda andrewda changed the title Reselect + Redux Actions + Immutable - WIP wip: add reselect, redux actions and immutable Aug 19, 2017
@alejandronanez alejandronanez changed the title wip: add reselect, redux actions and immutable wip: add reselect and redux actions Aug 19, 2017
@alejandronanez alejandronanez changed the title wip: add reselect and redux actions Add reselect and redux actions Aug 19, 2017
Copy link
Member

@housseindjirdeh housseindjirdeh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks so good @alejandronanez. Can't explain how much things are already looking cleaner.

Just left a few discussion points, but otherwise I can't see anything I would change outright.

};

export const organizationReducer = (state = initialState, action = {}) => {
switch (action.type) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OMG how have I not used redux-actions before, it looks so much cleaner 😍

@@ -1,5 +0,0 @@
import { createActionSet } from 'utils';

export const GET_ORG = createActionSet('GET_ORG');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice this is perfect, using redux-actions looks like we don't need a helper utility like createActionSet whatsoever


dispatch({ type: GET_ORG.PENDING });
export const getOrg = createAction(GET_ORG);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice agreed, makes things look so much more oganized 👍


export const getOrganization = createSelector(
getOrganizationFromStore,
organization => organization.organization || {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was having a disussion with colleagues from work this past week and a few were under the impression that when simply getting object parameters with dot notation doesn't necessarily need createSelector. For example, this would be sufficient:

export const getOrganization = state => state.organization.organization;

Not necessarily sure if I agree however. Majority of all our selectors are simple getters and not involve manipulation of data in anyway so it seems if we went with this approach we wouldn't really be using createSelector for the majority of our state.

Just wanted to get your input on this mate. Do you usually use createSelector for all data or only if you're retrieving data and performing manipulation to it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey dude! I usually use it to query the store and do some computations based on that data when needed. The big plus I see is that we can compose any selectors we want, for example combine one selector from organizations, one from repos and two from auth, then produce a new prop to pass to any component we want. I truly believe this is a good adition to the stack.

Here's a copy paste from reselect's site

Selectors can compute derived data, allowing Redux to store the minimal possible state.

Selectors are efficient. A selector is not recomputed unless one of its arguments change.

Selectors are composable. They can be used as input to other selectors.

@housseindjirdeh housseindjirdeh changed the title Add reselect and redux actions Add reselect and redux actions to organizations Aug 21, 2017
Copy link
Member

@housseindjirdeh housseindjirdeh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a million again for this <3<3<3<3<3<3<3<3

Should we have a separate issue open to track adding reselect and redux-actions to all the other parts of the app?

@housseindjirdeh housseindjirdeh merged commit 74bdd70 into master Aug 21, 2017
@alejandronanez alejandronanez deleted the immutable branch August 21, 2017 11:15
@alejandronanez
Copy link
Member Author

@housseindjirdeh yes! I think that's the right approach! 🙌🏼

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

Successfully merging this pull request may close these issues.

3 participants