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

WIP: createSlice() revision proposal #109

Closed
wants to merge 1 commit into from
Closed

WIP: createSlice() revision proposal #109

wants to merge 1 commit into from

Conversation

denisw
Copy link
Contributor

@denisw denisw commented Feb 5, 2019

To further the discussion about how to evolve createSlice (#91), I whipped I what I think would be an improved, but slightly different take on the slice concept.

Changes

  • The slice selector is removed. The selector makes strong assumptions about where the slice is mounted in the state tree, hindering comparability. It's also the least useful feature in that it saves very little code and is often not really needed. There is still a slice name parameter, but it's only used for action names-acing.

  • The slice is the reducer. Instead of representing the slice as an object that has a reducer property, now the slice is the reducer function itself. The action creators are still available as slice.actions. What's nice about this change is that you can pass slices directly to combineReducers or other reducer-composing functions.

  • Minor parameter naming tweaks. The slice parameter is now name, and reducers was renamed to actions to make it more different from extraReducers.

Example

// Basic Use //

const counterSlice = createSlice({
  name: 'counter',
  initialState: 0,
  actions: {
    increment: state => state + 1,
    multiply: (state, action) => state + action.payload
  }
})

const action = counterSlice.actions.increment()
counterSlice(undefined, action)
// => 1

// Composition //

const bagSlice = createSlice({
  name: 'bag',
  initialState: [],
  actions: {
    add: (state, action) => [...state, action.payload]
  }
})

// These slices are reducers, so `combineReducers` just works
const rootReducer = combineReducers({
  counter: counterSlice,
  bag: bagSlice
})

// There could be a combineSlices() that does the same as 
// above, but uses the slice names as object keys
const rootReducer = combineSlices(counterSlice, bagSlice)

Possible Improvements

  • Add a combineSlices function that combines slices into a reducer like combineReducers, but reads the object keys from the slice names.

  • Pass payloads directly to actions functions. createSlice generates the action creators, so we know that the payload is the only interesting thing about them. It's just easier for the user if we let them specify (state, payload) => state functions instead of (state, action) => state.

Feedback Welcome

This is meant as a first draft towards better slices. If you like the general direction this is moving towards, we can develop this further. Otherwise, let's find out what's good or bad about this and move on.

@netlify
Copy link

netlify bot commented Feb 5, 2019

Deploy preview for redux-starter-kit-docs ready!

Built with commit 9024664

https://deploy-preview-109--redux-starter-kit-docs.netlify.com

@denisw
Copy link
Contributor Author

denisw commented Feb 22, 2019

@markerikson Any thoughts on this?

@markerikson
Copy link
Collaborator

My attention is unfortunately very much focused on React-Redux stuff atm, so no, I haven't had time to think through this. (Also just got back from a 3-week business trip, and things are pretty hectic at work atm.)

Skimming this, I can get behind "slice" -> "name" and maybe making the reducer into the "slice" itself. I don't like changing "reducers" -> "actions". autodux uses "actions", and I specifically wanted to emphasis that this is about the reducer functions themselves.

I agree the slice selector is sort of appendix-ish in functionality atm, but I'd still like to find some kind of better approach for generating selectors somehow.

@agmcleod
Copy link

I like it. I can also respect wanting to keep reducers over actions if there's naming conflicts. Something else I'd love to have with actions, is someway to define them as global, but still have the other actions '${slice}/actionName'. Just been working on a single action to dispatch to delete data across multiple reducers.

@markerikson
Copy link
Collaborator

markerikson commented Feb 25, 2019

@agmcleod : I think that's where the extraReducers capability comes into play:

https://redux-starter-kit.js.org/api/createslice#extrareducers

const globalAction = createAction("doStuff");

const sliceA = createSlice({
    slice : "sliceA",
    extraReducers : {
        [globalAction]: (state, action) => {}
    }
});

const sliceB = createSlice({
    slice : "sliceB",
    extraReducers : {
        [globalAction]: (state, action) => {}
    }
});

@agmcleod
Copy link

Oh nice, yeah i missed that. I read up on them before, but i wasn't quite sure what they were for 😬

@markerikson
Copy link
Collaborator

markerikson commented Jul 6, 2019

Looking at this again. As mentioned, I agree with changing slice -> name, but don't like renaming reducers -> actions. I can probably get behind dropping the selector for now until we figure out a long-term plan.

Also, I don't want to pass payload directly to reducers, since A) other middleware could have modified the action, and B) we're looking at allowing meta customization.

Is there an actual benefit to making the "slice" be the reducer function itself?

@denisw
Copy link
Contributor Author

denisw commented Jul 11, 2019

@markerikson Thanks for the feedback. No problem with reverting the reducers->actions rename.

The one practical benefit of "the slice is the reducer" is that you can pass the slice directly to functions like combineReducers without having to remember to write slice.reducer - so, e.g., combineReducers({ key: theSlice.reducer }) becomes simply combineReducers({ key: theSlice }). Conceptually, it emphasizes the point that the reducer is the "main" part of the slice (as it defines and maintains the slice state).

@markerikson
Copy link
Collaborator

Superseded by #197 . @denisw , thanks for proposing these in the first place! Ultimately, I decided against the "return the reducer" aspect, but I appreciate the idea.

@markerikson markerikson closed this Oct 7, 2019
markerikson pushed a commit that referenced this pull request Apr 20, 2021
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

Successfully merging this pull request may close these issues.

3 participants