Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

RFC: configurableproduce implementation#3074

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
phryneas wants to merge28 commits intomaster
base:master
Choose a base branch
Loading
frompr/configure-produce-implementation

Conversation

@phryneas
Copy link
Member

@phryneasphryneas commentedJan 11, 2023
edited by markerikson
Loading

Withimmer alternatives likestructura.js,mutative, andlimu popping up, it might make sense to allow the configuration of theproduce implementation used by RTK.

This PR would, by default, still useimmer, 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 allowproduce to be swapped out for a stub, so people whoreally 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 useproduce, so additional changes would be required in

  • createEntityAdapter
  • createApi (here we need to configure with a version allowing for patches)

So 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 ofcreateSlice 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.

unadlib, giusepperaso, logankaser, mrkstwrt, thomasjahoda, aeharding, AlessandroSteri, akaltar, its-monotype, and louwers reacted with thumbs up emoji
@codesandbox
Copy link

CodeSandbox logoCodeSandbox logo  Open in CodeSandboxWeb Editor |VS Code |VS Code Insiders

@codesandbox-ci
Copy link

codesandbox-cibot commentedJan 11, 2023
edited
Loading

This pull request is automatically built and testable inCodeSandbox.

To see build info of the built libraries, clickhere or the icon next to each commit SHA.

Latest deployment of this branch, based on commit0888fde:

SandboxSource
VanillaConfiguration
Vanilla TypescriptConfiguration
rsk-github-issues-exampleConfiguration
@examples-query-react/basicConfiguration
@examples-query-react/advancedConfiguration
@examples-action-listener/counterConfiguration
rtk-esm-craConfiguration

@unadlib
Copy link

unadlib commentedJan 11, 2023
edited
Loading

hi@phryneas,

I will add support for return values tomutative. 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.

@phryneas
Copy link
MemberAuthor

phryneas commentedJan 11, 2023
edited
Loading

Hi@unadlib! That's great news!
Inwriting reducers withimmer (which we might need to rename to "writing mutable immutable reducers" or something like that), we generally recommend changing the existing state - but there are cases where the user might want to return something completely different.

Most common cases would be:

  • replacing the full state with a completely new object (e.g. resetting state or taking a big chunk of data that came in, for example from an api call)
  • the user wants to optimize things by hand
  • they are just migrating over old Redux code that is not doing mutable updates yet.

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.

@unadlib
Copy link

unadlib commentedJan 14, 2023
edited
Loading

Hi@unadlib! That's great news! Inwriting reducers withimmer (which we might need to rename to "writing mutable immutable reducers" or something like that), we generally recommend changing the existing state - but there are cases where the user might want to return something completely different.

Most common cases would be:

  • replacing the full state with a completely new object (e.g. resetting state or taking a big chunk of data that came in, for example from an api call)
  • the user wants to optimize things by hand
  • they are just migrating over old Redux code that is not doing mutable updates yet.

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 optionstrict, which we will suggest the user enablestrict in development mode and disablestrict in production mode. This will ensure safe returns and also keep good performance in the production build.

If the return value is mixed drafts orundefined, then usesafeReturn() wrapper.

phryneas reacted with thumbs up emoji

// Ensure the initial state gets frozen either way (if draftable)
letgetInitialState:()=>S
if(isStateFunction(initialState)){
getInitialState=()=>freezeDraftable(initialState())
Copy link
Collaborator

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

@markeriksonmarkeriksonforce-pushed thev2.0-integration branch 2 times, most recently from606897f tod2d0f70CompareJanuary 14, 2023 18:18
@unadlib
Copy link

unadlib commentedJan 26, 2023
edited
Loading

@phryneas@markerikson Mutative v0.3.2 already supports returning values in the draft functions. It is already fully compliant withproduce interface inredux-toolkit and maintains good performance.

@markerikson
Copy link
Collaborator

@unadlib : nice!

One other question that came up is that we use several of Immer's utilities likeisDraft andisDraftable, in order to check whether it's safe to pass certain values intoproduce().

Doesmutative have anything like those?

@unadlib
Copy link

unadlib commentedJan 27, 2023
edited
Loading

@unadlib : nice!

One other question that came up is that we use several of Immer's utilities likeisDraft andisDraftable, in order to check whether it's safe to pass certain values intoproduce().

Doesmutative have anything like those?

@markerikson Yes, Mutative also providesisDraft() andisDraftable().

markerikson reacted with thumbs up emoji

@markeriksonmarkeriksonforce-pushed thepr/configure-produce-implementation branch from0ce2ec0 tocd99badCompareFebruary 21, 2023 04:38
@markeriksonmarkeriksonforce-pushed thepr/configure-produce-implementation branch fromcd99bad toef49075CompareFebruary 21, 2023 04:40
@markerikson
Copy link
Collaborator

markerikson commentedFeb 21, 2023
edited
Loading

I rebased this branch againstv2.0-integration.

Also, for kicks, I tried swapping all our usages of Immer to use Mutative instead. Unfortunately, there's several critical test failures, including basiccreateReducer behavior. Looks like it's hitting aCannot perform 'has' on a proxy that has been revoked error.

https://github.com/reduxjs/redux-toolkit/tree/feature/try-mutative

@unadlib
Copy link

I rebased this branch againstv2.0-integration.

Also, for kicks, I tried swapping all our usages of Immer to use Mutative instead. Unfortunately, there's several critical test failures, including basiccreateReducer behavior. Looks like it's hitting aCannot perform 'has' on a proxy that has been revoked error.

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.

@unadlib
Copy link

I rebased this branch againstv2.0-integration.

Also, for kicks, I tried swapping all our usages of Immer to use Mutative instead. Unfortunately, there's several critical test failures, including basiccreateReducer behavior. Looks like it's hitting aCannot perform 'has' on a proxy that has been revoked error.

https://github.com/reduxjs/redux-toolkit/tree/feature/try-mutative

For good performance, Mutative does not traverse mixed draft return values by default. When the return value is mixed with drafts, you can usesafeReturn().

Mutative docs:

We recommend to enable strict in development mode and disable strict in production mode. This will ensure safe returns and also keep good performance in the production build. If the return value is mixed drafts or undefined, then usesafeReturn().

You can fix tests like this,

https://github.com/reduxjs/redux-toolkit/blob/feature/try-mutative/packages/toolkit/src/tests/createReducer.test.ts#L174

- return state.concat({ ...newTodo, completed: false })+ return safeReturn(state.concat({ ...newTodo, completed: false }))

https://github.com/reduxjs/redux-toolkit/blob/feature/try-mutative/packages/toolkit/src/tests/createReducer.test.ts#L181

- return state.map((todo, i) => {+ return safeReturn(state.map((todo, i) => {

@markerikson
Copy link
Collaborator

Hmm. That definitely makes it harder to usemutative as a drop-in replacement, because we don't know ahead of time what users are going to do in their reducers.

Ithink the right answer here is that we'd need to inject a wrapper that usessafeReturn, something like:

constcreateReducerWithMutative=buildCreateReducer({createNextState:(state,recipe)=>{returncreate(state,(draft)=>{returnsafeReturn(recipe(draft))})},  isDraft,  isDraftable})
unadlib reacted with thumbs up emoji

@unadlib
Copy link

Hmm. That definitely makes it harder to usemutative as a drop-in replacement, because we don't know ahead of time what users are going to do in their reducers.

Ithink the right answer here is that we'd need to inject a wrapper that usessafeReturn, something like:

constcreateReducerWithMutative=buildCreateReducer({createNextState:(state,recipe)=>{returncreate(state,(draft)=>{returnsafeReturn(recipe(draft))})},  isDraft,  isDraftable})

When the user usescreateReducerWithImmer, if the reducer wants to return the valueundefined, the reducer will have to return return Immer'snothing, and this implicit rule is similar to the case.

I also agree with you. WhethercreateReducerWithMutative returnsundefined explicitly or not is left up to the user, like this.

constcreateReducerWithMutative=buildCreateReducer({createNextState:(state,recipe)=>{returncreate(state,(draft)=>{constvalue=recipe(draft);returnvalue===undefined ?value :safeReturn(value);})},  isDraft,  isDraftable})

@markeriksonmarkeriksonforce-pushed thev2.0-integration branch 2 times, most recently from1348302 to157536cCompareMarch 25, 2023 18:58
@unadlib
Copy link

@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 atunadlib/mutative#9

BTW, I tested the Immer v10 branch. Mutative is still more than 15x faster than Immer.

@giusepperaso
Copy link

giusepperaso commentedApr 1, 2023
edited
Loading

Hi, I'm the author ofstructurajs. 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 atry-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 theexports.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:

  • structura does not allow the produced state to be modified (at compile time via typescript), so relying on object freeze could be a bit redundant
  • structura by default does not use standard json patches, but a proprietary format based on linked lists which is slightly faster; you probably don't need standard json patches unless you have to manipulate them with another library

If you see any problem or if you need help with something let me know!@phryneas@markerikson

@markerikson
Copy link
Collaborator

@giusepperaso : thanks for working on that!

FWIW we reallydo want freezing in place, because wewant users to see errors at runtime if they attempt to mutate outside of a reducer. (Not everyone uses TS!)

giusepperaso reacted with thumbs up emoji

@EskiMojo14
Copy link
Collaborator

is it worth making a configurable version of createDraftSafeSelector too? that currently uses immer's isDraft() and current()

ben.durrantand others added14 commitsApril 5, 2023 11:35
@markeriksonmarkerikson added this to thePost 2.0 milestoneOct 1, 2023
@netlify
Copy link

netlifybot commentedOct 2, 2023

Deploy Preview forredux-starter-kit-docs ready!

NameLink
🔨 Latest commit0888fde
🔍 Latest deploy loghttps://app.netlify.com/sites/redux-starter-kit-docs/deploys/651b2b31e7e2f100084383b4
😎 Deploy Previewhttps://deploy-preview-3074--redux-starter-kit-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to yourNetlify site configuration.

@markerikson
Copy link
Collaborator

Found another similar lib:https://github.com/tnfe/limu

Base automatically changed fromv2.0-integration tomasterDecember 4, 2023 04:51
@unadlib
Copy link

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 theredux-toolkit. So maybe I could provide an additional Mutative lib based on theredux-toolkit?

But, if there are further plans for this proposal, I would be very happy to participate.

thomasjahoda reacted with heart emoji

@markerikson
Copy link
Collaborator

@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.)

unadlib reacted with eyes emoji

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@markeriksonmarkeriksonmarkerikson left review comments

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

Post 2.0

Development

Successfully merging this pull request may close these issues.

6 participants

@phryneas@unadlib@markerikson@giusepperaso@EskiMojo14

[8]ページ先頭

©2009-2025 Movatter.jp