How to update single value inside specific array item in redux

前端 未结 8 1305
隐瞒了意图╮
隐瞒了意图╮ 2020-11-28 01:55

I have an issue where re-rendering of state causes ui issues and was suggested to only update specific value inside my reducer to reduce amount of re-rendering on a page.

相关标签:
8条回答
  • 2020-11-28 02:18

    I'm afraid that using map() method of an array may be expensive since entire array is to be iterated. Instead, I combine a new array that consists of three parts:

    • head - items before the modified item
    • the modified item
    • tail - items after the modified item

    Here the example I've used in my code (NgRx, yet the machanism is the same for other Redux implementations):

    // toggle done property: true to false, or false to true
    
    function (state, action) {
        const todos = state.todos;
        const todoIdx = todos.findIndex(t => t.id === action.id);
    
        const todoObj = todos[todoIdx];
        const newTodoObj = { ...todoObj, done: !todoObj.done };
    
        const head = todos.slice(0, todoIdx - 1);
        const tail = todos.slice(todoIdx + 1);
        const newTodos = [...head, newTodoObj, ...tail];
    }
    
    0 讨论(0)
  • 2020-11-28 02:22

    You don't have to do everything in one line:

    case 'SOME_ACTION':
      const newState = { ...state };
      newState.contents = 
        [
          newState.contents[0],
          {title: newState.contnets[1].title, text: action.payload}
        ];
      return newState
    
    0 讨论(0)
  • 2020-11-28 02:25

    You could use the React Immutability helpers

    import update from 'react-addons-update';
    
    // ...    
    
    case 'SOME_ACTION':
      return update(state, { 
        contents: { 
          1: {
            text: {$set: action.payload}
          }
        }
      });
    

    Although I would imagine you'd probably be doing something more like this?

    case 'SOME_ACTION':
      return update(state, { 
        contents: { 
          [action.id]: {
            text: {$set: action.payload}
          }
        }
      });
    
    0 讨论(0)
  • 2020-11-28 02:25

    Very late to the party but here is a generic solution that works with every index value.

    1. You create and spread new array from the old array up to the index you want to change.

    2. Add the data you want.

    3. Create and spread new array from the index you wanted to change to the end of the array

    let index=1;// probabbly action.payload.id
    case 'SOME_ACTION':
       return { 
           ...state, 
           contents: [
              ...state.contents.slice(0,index),
              {title: "some other title", text: "some other text"},
             ...state.contents.slice(index+1)
             ]
        }
    

    Update:

    I have made a small module to simplify the code, so you just need to call a function:

    case 'SOME_ACTION':
       return {
           ...state,
           contents: insertIntoArray(state.contents,index, {title: "some title", text: "some text"})
        }
    

    For more examples, take a look at the repository

    function signature:

    insertIntoArray(originalArray,insertionIndex,newData)
    
    0 讨论(0)
  • 2020-11-28 02:27

    You can use map. Here is an example implementation:

    case 'SOME_ACTION':
       return { 
           ...state, 
           contents: state.contents.map(
               (content, i) => i === 1 ? {...content, text: action.payload}
                                       : content
           )
        }
    
    0 讨论(0)
  • 2020-11-28 02:33

    I believe when you need this kinds of operations on your Redux state the spread operator is your friend and this principal applies for all children.

    Let's pretend this is your state:

    const state = {
        houses: {
            gryffindor: {
              points: 15
            },
            ravenclaw: {
              points: 18
            },
            hufflepuff: {
              points: 7
            },
            slytherin: {
              points: 5
            }
        }
    }
    

    And you want to add 3 points to Ravenclaw

    const key = "ravenclaw";
      return {
        ...state, // copy state
        houses: {
          ...state.houses, // copy houses
          [key]: {  // update one specific house (using Computed Property syntax)
            ...state.houses[key],  // copy that specific house's properties
            points: state.houses[key].points + 3   // update its `points` property
          }
        }
      }
    

    By using the spread operator you can update only the new state leaving everything else intact.

    Example taken from this amazing article, you can find almost every possible option with great examples.

    0 讨论(0)
提交回复
热议问题