如何在redux中更新特定数组项中的单个值

Ilj*_*lja 85 javascript reactjs redux

我有一个问题,重新呈现状态会导致ui问题,并建议只更新我的reducer中的特定值,以减少页面上的重新呈现量.

这是我的州的例子

{
 name: "some name",
 subtitle: "some subtitle",
 contents: [
   {title: "some title", text: "some text"},
   {title: "some other title", text: "some other text"}
 ]
}
Run Code Online (Sandbox Code Playgroud)

我目前正在更新它

case 'SOME_ACTION':
   return { ...state, contents: action.payload }
Run Code Online (Sandbox Code Playgroud)

where action.payload是包含新值的整个数组.但是现在我实际上只需要更新内容数组中第二项的文本,这样的东西不起作用

case 'SOME_ACTION':
   return { ...state, contents[1].text: action.payload }
Run Code Online (Sandbox Code Playgroud)

action.payload现在我需要更新的文本在哪里.

Fat*_*kli 144

你可以用map.这是一个示例实现:

case 'SOME_ACTION':
   return { 
       ...state, 
       contents: state.contents.map(
           (content, i) => i === 1 ? {...content, text: action.payload}
                                   : content
       )
    }
Run Code Online (Sandbox Code Playgroud)

  • 我经常这样做,但迭代所有元素而不是更新必要的索引在计算上似乎相对昂贵. (8认同)
  • 我认为这是最好的方法 (2认同)
  • 这与内存成本无关。这是关于不会因进入指数循环而减慢应用程序的速度 (2认同)

Cla*_*kie 47

您可以使用React Immutability帮助程序

import update from 'react-addons-update';

// ...    

case 'SOME_ACTION':
  return update(state, { 
    contents: { 
      1: {
        text: {$set: action.payload}
      }
    }
  });
Run Code Online (Sandbox Code Playgroud)

虽然我想你可能会做更像这样的事情?

case 'SOME_ACTION':
  return update(state, { 
    contents: { 
      [action.id]: {
        text: {$set: action.payload}
      }
    }
  });
Run Code Online (Sandbox Code Playgroud)

  • 虽然这个软件包已经转移到`kolodny/immutability-helper`,所以现在它是`yarn add immutability-helper`和`import immut from'immutability-helper';` (7认同)

Yuy*_*uya 16

您不必在一行中完成所有操作:

case 'SOME_ACTION':
  const newState = { ...state };
  newState.contents = 
    [
      newState.contents[0],
      {title: newState.contnets[1].title, text: action.payload}
    ];
  return newState
Run Code Online (Sandbox Code Playgroud)

  • 将您的案例正文包装在{}中,因为const是块作用域的。 (2认同)

Lui*_*uez 8

我相信当你需要在你的 Redux 状态上进行这种操作时,spread 操作符是你的朋友,这个原则适用于所有孩子。

让我们假设这是您的状态:

const state = {
    houses: {
        gryffindor: {
          points: 15
        },
        ravenclaw: {
          points: 18
        },
        hufflepuff: {
          points: 7
        },
        slytherin: {
          points: 5
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

而你想给拉文克劳加3分

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
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

通过使用扩展运算符,您可以仅更新新状态,而其他所有内容均保持不变。

来自这篇精彩文章的示例,您可以找到几乎所有可能的选项以及很好的示例。

  • 当OP想要更新数组时,这对我来说看起来像是一个对象 (2认同)

Nea*_*arl 8

这在 redux-toolkit 中非常简单,它使用 Immer 帮助你编写看起来像可变的不可变代码,更简洁、更容易阅读。

// it looks like the state is mutated, but under the hood Immer keeps track of
// every changes and create a new state for you
state.x = newValue;
Run Code Online (Sandbox Code Playgroud)

因此不必在普通的 redux 减速器中使用展开运算符

return { 
  ...state, 
  contents: state.contents.map(
      (content, i) => i === 1 ? {...content, text: action.payload}
                              : content
  )
}
Run Code Online (Sandbox Code Playgroud)

您只需重新分配本地值,然后让 Immer 为您处理其余的事情:

state.contents[1].text = action.payload;
Run Code Online (Sandbox Code Playgroud)

现场演示

编辑35628774/如何在redux中更新特定数组项内的单值


Iva*_* V. 5

派对很晚,但是这里有一个通用解决方案,适用于每个索引值。

  1. 您可以创建新阵列并将其从旧阵列传播到index要更改的阵列。

  2. 添加所需的数据。

  3. index要更改的阵列创建并传播新阵列,直到阵列的末尾

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)
         ]
    }
Run Code Online (Sandbox Code Playgroud)