195

What is the better way to update state in this context inside a reducer?

case DELETE_INTEREST:
    let deleteInterests = state.user.interests;
    let index = deleteInterests.findIndex(i => i == action.payload);
    deleteInterests.splice(index, 1);
    return { ...state, user: { ...state.user, interests: deleteInterests } };

ESLint doesn't like let statements inside case blocks inside a reducer, getting:

eslint: no-case-declaration - unexpected lexical declaration in case block

Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
Josh
  • 2,430
  • 4
  • 18
  • 30
  • 1
    `deleteInterests` is still a reference to the array in state so you're still mutating. Clone the list before splicing. – Andrew Li Jun 08 '18 at 03:37
  • 4
    Use `{}` for the `case DELETE_INTEREST` in `switch` to get rid of this lint issue as per, https://eslint.org/docs/rules/no-case-declarations – Himanshu Aggarwal Apr 13 '20 at 07:47

3 Answers3

443

ESLint doesn't like let statements inside case blocks inside a reducer, Why?

This is discouraged because it results in the variable being in scope outside of your current case. By using a block you limit the scope of the variable to that block.

Use {} to create the block scope with case, like this:

case DELETE_INTEREST: {
    let .....
    return (...)
}

Check this snippet:

function withOutBraces() { 
  switch(1){
    case 1: 
      let a=10; 
      console.log('case 1', a); 
    case 2: 
      console.log('case 2', a)
  } 
}

function withBraces() { 
  switch(1){
    case 1: {
      let a=10; 
      console.log('case 1', a); 
    }
    case 2: {
      console.log('case 2', a)
    }
  } 
}

console.log('========First Case ============')
withOutBraces()
console.log('========Second Case ============')
withBraces();

For deleting the element from array, use array.filter, because splice will do the changes in original array. Write it like this:

case DELETE_INTEREST:
    let deleteInterests = state.user.interests;
    let newData = deleteInterests.filter(i => i !== action.payload);
    return { ...state, user: { ...state.user, interests: newData } };
Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
  • 9
    Why, though? :) – nsandersen Sep 10 '19 at 15:54
  • 6
    From what I understood, if you declare a variable inside a `case` block without scoping it with `{}` your variable will be available in the switch block but will only be assigned in that case block (there's a risk it won't be declared if it doesn't go through that case) https://eslint.org/docs/rules/no-case-declarations – PaulCo Dec 02 '20 at 09:02
23

try to encapsulate the inside the case with {} like this look simple example

      case EnumCartAction.DELETE_ITEM: {
           const filterItems = state.cart.filter((item) => item._id !== action.payload)
           return {
                ...state,
                cart: filterItems
           }
      }
Mohammed Al-Reai
  • 2,344
  • 14
  • 18
2

An easy fix is to use brackets {} to encapsulate your case code. If you're using return you might need to add break in some cases.

clemncls
  • 21
  • 2