-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
RFC: configurable produce
implementation
#3074
base: master
Are you sure you want to change the base?
Conversation
Open in CodeSandbox Web Editor | VS Code | VS Code Insiders |
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 0888fde:
|
hi @phryneas, I will add support for return values to mutative. But from the user's point of view, we should suggest always returning the draft itself or no value at all, not only does it maintain optimal performance (no extra performance wasted traversing unpredictable return values), but it also maintains the full mutation feature. |
Hi @unadlib! That's great news! Most common cases would be:
From our perspective it would be fine if the rule were "if the user returns a value and that value is not the draft, just return that whole new value without traversing and touching it in any way", but I'm not sure if there are additional things that you have to do and cannot skip. |
Cool proposal. Since the user may refer to the draft in the return of a completely new object, I will use the option If the return value is mixed drafts or |
// Ensure the initial state gets frozen either way (if draftable) | ||
let getInitialState: () => S | ||
if (isStateFunction(initialState)) { | ||
getInitialState = () => freezeDraftable(initialState()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✋ This still relies on Immer imports over in ./utils
606897f
to
d2d0f70
Compare
@phryneas @markerikson Mutative v0.3.2 already supports returning values in the draft functions. It is already fully compliant with |
@unadlib : nice! One other question that came up is that we use several of Immer's utilities like Does |
@markerikson Yes, Mutative also provides |
0ce2ec0
to
cd99bad
Compare
cd99bad
to
ef49075
Compare
I rebased this branch against Also, for kicks, I tried swapping all our usages of Immer to use Mutative instead. Unfortunately, there's several critical test failures, including basic https://github.com/reduxjs/redux-toolkit/tree/feature/try-mutative |
hi, @markerikson, I will debug it later. Overall, regarding the integration with Reducer, Immer and Mutative are not exactly equivalent, Mutative supports more options. |
For good performance, Mutative does not traverse mixed draft return values by default. When the return value is mixed with drafts, you can use
You can fix tests like this, - return state.concat({ ...newTodo, completed: false })
+ return safeReturn(state.concat({ ...newTodo, completed: false })) - return state.map((todo, i) => {
+ return safeReturn(state.map((todo, i) => { |
Hmm. That definitely makes it harder to use I think the right answer here is that we'd need to inject a wrapper that uses const createReducerWithMutative = buildCreateReducer({
createNextState: (state, recipe) => {
return create(state, (draft) => {
return safeReturn(recipe(draft))
})
},
isDraft,
isDraftable
}) |
When the user uses I also agree with you. Whether const createReducerWithMutative = buildCreateReducer({
createNextState: (state, recipe) => {
return create(state, (draft) => {
const value = recipe(draft);
return value === undefined ? value : safeReturn(value);
})
},
isDraft,
isDraftable
}) |
1348302
to
157536c
Compare
@markerikson I have refactored the implementation of the return value, once you upgrade to mutative v0.5.0, you will migrate Immer to Mutative smoothly, the relevant tests have passed. The details are at unadlib/mutative#9 BTW, I tested the Immer v10 branch. Mutative is still more than 15x faster than Immer. |
Hi, I'm the author of structurajs. Thanks for this pull request! After some work I think I finally managed to make the library fully compatible with redux toolkit As an example I did setup a try-structura branch which passes all of the tests contained into the packages/toolkit folder Note that in this example branch I removed Immer completely, and I put all of my exports inside the exports.ts file Also, I called enableAutoFreeze and enableStandardPatches to make all of the tests pass, but they are not always necessary and could be disabled to gain some performance:
If you see any problem or if you need help with something let me know! @phryneas @markerikson |
@giusepperaso : thanks for working on that! FWIW we really do want freezing in place, because we want users to see errors at runtime if they attempt to mutate outside of a reducer. (Not everyone uses TS!) |
is it worth making a configurable version of createDraftSafeSelector too? that currently uses immer's isDraft() and current() |
✅ Deploy Preview for redux-starter-kit-docs ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
Found another similar lib: https://github.com/tnfe/limu |
Hi, I'm not sure if there are any next steps planned for this proposal. Currently, the performance test information related to Immer and Mutative is as follows:
Perhaps performance improvement is not a high priority for the But, if there are further plans for this proposal, I would be very happy to participate. |
@unadlib it's still an idea I'm interested in conceptually, but it's not on our roadmap to work on this any time soon. (I haven't had time to work on much RTK stuff lately, and when I do my focus will be on RTK Query features.) |
With
immer
alternatives like structura.js and mutative popping up, it might make sense to allow the configuration of theproduce
implementation used by RTK.This PR would, by default, still use
immer
, but exposebuildCreateReducer
andbuildCreateSlice
functions to create customcreateReducer
andcreateSlice
functions. This should tree-shake well, and if only those other implementations are used,immer
should not be bundled anymore (as soon as the polyfill in 2.0 is disabled, which is why I base this PR against the v2 version).This would also theoretically allow
produce
to be swapped out for a stub, so people who really want to use RTK without any immutability helper could do so - even though I would highly recommend against that.It would also prepare for future situations when Records and Tuples are widely available, and an immutability helper will not be necessary anymore.
There are still a few more places where we use
produce
, so additional changes would be required inSo far, I just wanted to put this out as a base for discussion - the code changes required for this are pretty small, so I think it might make sense at this point.
PS: we might need to do some docs updates, as, at the moment, the docs directly reference the types of
createSlice
and that has now moved into its own interface definition.PS2: at this point,
mutative
does not allow for returning a new object, so that one might not work yet. Let's see if we can convince the author to add that functionality.