0

I am coding along with the Redux Essentials tutorial.

When I run notificationArray.map without using the return value, my state is updated per the map functions callbacks.

I.e. in allNotifiicationsRead, each notifications's read property is set to true in the app state. And in fetchNotifications, all each notification's isNew property is set to !read.

I would expect this notificationArray.map(...) call to not have any effect since, I am not using the return value, let alone editing the state with it such as something like notificationsAdapter.setMany(notificationArray).

Any clarification on how this is working would be appreciated.

Please let me know if I didn't include any relevant details about this app.

const notificationsSlice = createSlice({
    name: 'notifications',
    initialState: notificationsAdapter.getInitialState(),
    reducers: {
        allNotificationsRead(state, action) {
            const notificationArray = Object.values(state.entities)
            notificationArray.map(notification => (
                notification.read = true
            ))
        }
    },
    extraReducers(builder){
        builder.addCase(fetchNotifications.fulfilled, (state, action) => {
            notificationsAdapter.upsertMany(state, action.payload)
            const notificationArray = Object.values(state.entities)
            notificationArray.map(notification => (
                notification.isNew = !notification.read
            ))
        })
    }
})
7
  • You did not assign the Array#map product to anything. Commented Jun 1, 2022 at 21:05
  • First of all you shouldn't be using map() without a return as that is simply a forEach() with additional overhead, but the reason it's mutating your state is that you are directly changing a nested object's properties. map doesn't clone the contents of the array it's called on in any way. To avoid the mutation you should be using the returned array from the map() and you should be cloning each object in the callback const notificationArray = Object.values(state.entities).map(notification => ({...notification, isNew: !notification.read})); Commented Jun 1, 2022 at 21:06
  • If you don't want to mutate the array, you shouldn't have statements that mutate (like notification.read = true). The alternative is to copy, but then where do you want to store it -- since you made notificationArray a const? Commented Jun 1, 2022 at 21:08
  • see: JavaScript: Difference between .forEach() and .map() and How to mutate original array in Javascript .map() function? Commented Jun 1, 2022 at 21:11
  • @pilchard Thank you, you explained this behavior perfectly. I didn't recognize here that I was simply modifying the array by writing .map(notification => (...)) instead of cloning each object with .map(notification => ({...})). It seems like the former will always lead to modifying the original array (as well as not returning a modified array) and therefore an antipattern. Can you point me to a resource that explains exactly what the syntax being used in each is? I.e. .map(notification => (...)) modifies the array whereas .map(notification => ({...})) clones each item. Commented Jun 1, 2022 at 22:12

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.