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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35628774/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 18:02:24  来源:igfitidea点击:

How to update single value inside specific array item in redux

javascriptreactjsredux

提问by Ilja

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.

我有一个问题,重新渲染状态会导致 ui 问题,并且建议仅更新我的减速器中的特定值以减少页面上的重新渲染量。

this is example of my state

这是我所在州的例子

{
 name: "some name",
 subtitle: "some subtitle",
 contents: [
   {title: "some title", text: "some text"},
   {title: "some other title", text: "some other text"}
 ]
}

and I am currently updating it like this

我目前正在像这样更新它

case 'SOME_ACTION':
   return { ...state, contents: action.payload }

where action.payloadis a whole array containing new values. But now I actually just need to update text of second item in contents array, and something like this doesn't work

其中action.payload是包含新值的整个数组。但现在我实际上只需要更新内容数组中第二项的文本,而这样的事情是行不通的

case 'SOME_ACTION':
   return { ...state, contents[1].text: action.payload }

where action.payloadis now a text I need for update.

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

采纳答案by Clarkie

You could use the React Immutability helpers

你可以使用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}
      }
    }
  });

回答by Fatih Erikli

You can use map. Here is an example implementation:

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

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

回答by Yuya

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

回答by Ivan V.

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 indexyou want to change.

  2. Add the data you want.

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

  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)
         ]
    }

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)

回答by Erfan226

In my case I did something like this, based on Luis's answer:

就我而言,根据路易斯的回答,我做了类似的事情:

...State object...
userInfo = {
name: '...',
...
}

...Reducer's code...
case CHANGED_INFO:
return {
  ...state,
  userInfo: {
    ...state.userInfo,
    // I'm sending the arguments like this: changeInfo({ id: e.target.id, value: e.target.value }) and use them as below in reducer!
    [action.data.id]: action.data.value,
  },
};

回答by Luis Rodriguez

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

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

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

而你想给拉文克劳加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
      }
    }
  }

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.

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

回答by TazExprez

This is how I did it for one of my projects:

这就是我为我的一个项目所做的:

const markdownSaveActionCreator = (newMarkdownLocation, newMarkdownToSave) => ({
  type: MARKDOWN_SAVE,
  saveLocation: newMarkdownLocation,
  savedMarkdownInLocation: newMarkdownToSave  
});

const markdownSaveReducer = (state = MARKDOWN_SAVED_ARRAY_DEFAULT, action) => {
  let objTemp = {
    saveLocation: action.saveLocation, 
    savedMarkdownInLocation: action.savedMarkdownInLocation
  };

  switch(action.type) {
    case MARKDOWN_SAVE:
      return( 
        state.map(i => {
          if (i.saveLocation === objTemp.saveLocation) {
            return Object.assign({}, i, objTemp);
          }
          return i;
        })
      );
    default:
      return state;
  }
};