问题
Im not sure why I'm getting Error: Immer drafts cannot have computed properties in my reducer code. I'm using redux-starter-kit which wraps all my reducer code with the Immer library.
I'm not entirely sure what Immer is referring to with "computed property." Does it mean getters/setters? Because I'm not creating any getters or setters explicitly. Is the object spread operator doing it?
Do getters/setters contaminate the state object somehow?
Or is computed property in reference to computed property names? https://tylermcginnis.com/computed-property-names/
My reducer is fairly simple:
import { createSlice } from 'redux-starter-kit'
const assets = createSlice({
slice: 'assets',
initialState: {byName: {}},
reducers: {
upload: (state, action) => {
const {name} = action.payload;
state.byName[name].status = 'uploading';
},
initialize: (state, action) => {
const {assets, id} = action.payload;
assets.forEach(({name, uri}) => {
state.byName[name] = {
uri,
name,
status: 'local',
id,
inProgress: true
};
});
},
}
})
export default assets;
The assets/initialize action is triggered first with no error, and the immer error occurs when the assets/upload action is triggered
I'm not sure where all those get name / set name, get uri / set uri fields are coming from. Is that what Immer is complaining about?
I rewrote the upload reducer to create a new object,
upload: (state, action) => {
const {name} = action.payload;
state.byName[name] = {
...state.byName[name],
status: 'uploading',
};
},
and the error I get now is equally baffling:
回答1:
I'm not sure where all those get name / set name, get uri / set uri fields are coming from. Is that what Immer is complaining about?
These "fields" come from Redux, and yes, that's what Immer is complaining about. They're called Acessors - but mostly known as Getter and Setter - which were introduced in ES5. This is by design Redux's way to work with state, which is to mutate the object and track changes through these functions - your reducers become setters, and selectors become getters. Now Immer's approach is to provide an immutable state tree, providing a new object on every state change.
Immer complains about these acessors because there's no way to clone object with functions 100% reliably, as these may be accessing lexically-scoped private variables through closures, i.e. these function bodies variable references would point to the previous state (more on that on "how do javascript closures work"). And this isn't an Immer-specific problem, it is the very specification of how the JavaScript structured clone algorithm work. As per MDN comment on the structured clone algorithm:
The structured clone algorithm is an algorithm defined by the HTML5 specification for copying complex JavaScript objects. (...)
Things that don't work with structured cloneSection
- Error and Function objects cannot be duplicated by the structured clone algorithm; attempting to do so will throw a DATA_CLONE_ERR exception.
- Attempting to clone DOM nodes will likewise throw a DATA_CLONE_ERR exception.
- Certain parameters of objects are not preserved:
- The lastIndex field of RegExp objects is not preserved.
- Property descriptors, setters, and getters (as well as similar metadata-like features) are not duplicated. For example, if an object is marked read-only using a property descriptor, it will be read-write in the duplicate, since that's the default condition.
- The prototype chain does not get walked and duplicated.
Note that prototype computed property names do work with Immer if you set it as "immerable" with prototype[immerable] = true, but that's not the case here.
来源:https://stackoverflow.com/questions/57505319/immer-drafts-computed-properties