我如何使用ES6 ...表示法?

时间:2016-06-17 20:49:28

标签: javascript reactjs ecmascript-6 redux

我很反应和es6语法。我在我的反应网络应用程序中使用redux,在我的reducer中,我希望能够将字符串推送到我的state.likes

这是我的代码:

const i = action.index;
console.log(state);
return [
    ...state.slice(0, i), // before the one we are updating
    {...state[i], likes: state[i].likes+1}, //i want to change this bit so I can push deviceKey
    ...state.slice(i+1), //after one we are updating
  ]

当我console.log(state)时,我在这个数组中有两个对象:

[
{
  "code": "AAAAAAA",
  "caption": "blah blah blah",
  "likes": [
    "ABCDEFG",
    "BACDEFG"
  ],
  "id": "1234567890",
  "display_src": "https://pbs.twimg.com/profile_images/1044686525/Get_Some.jpg"
},
{
  "code": "BBBBBBB",
  "caption": "nah fam",
  "likes": [
    "ABCDEFG",
    "BACDEFG",
    "CBADEFG"
  ],
  "id": "0987654321",
  "display_src": 'http://got-crossfit.com/wp-content/uploads/2014/04/get-some-rest.jpg'
}
]

现在,每当此减速器触发时,我如何将action.deviceKey推入state[i].likes?我试过了{...state[i], likes: state[i].likes.push(action.deviceKey)},但它没有用。

也可以有人eli5 ...符号吗?我仍然不明白这是什么意思。

谢谢!

3 个答案:

答案 0 :(得分:2)

实际上有三种不同的方式...可以使用。从技术上讲,其中只有一个是有效的官方Javascript,但其他两个非常常见。

所有这些都用于制作"浅拷贝"对象和数组。浅拷贝是在创建新对象或数组时,但在其中包含与原始对象完全相同的项/数据/引用。

首先,...可以用作"数组传播" operator,用于制作数组的浅表副本。到目前为止,这是实际Javascript规范的唯一形式。它与Array.slice()基本相同。

其次,...可以在JSX语法中使用(由React引入,也可以由其他类似的视图库使用)。它是对象的浅表副本。

最后,有一项官方建议使用...作为"对象传播"运算符可以在Javascript代码中的任何位置创建对象的浅表副本,而不仅仅是在JSX中。该提议尚未最终确定,但许多人通过使用Babel插件将其编译为等效的Object.assign()函数调用来使用它。

对于您的具体问题,我认为您需要使用Array.concat()函数,该函数返回包含新项目的新数组引用,而不是Array.push()函数,该函数将项目插入到现有阵列。

答案 1 :(得分:1)

点差运营商(...)并没有完全按照您的想法行事。因此,根据ECMAScript定义,它是迭代Objects可枚举属性的一种方式。您的状态设计非常糟糕,但随着您的复杂性增加,这将很难管理。

数组传播运算符

这只是迭代一个数组,作为从现有数组创建新数组的简单方法。请考虑以下事项:

const old = ['b', 'c'];
const newArr = ['a', ...old, 'd']; // ['a', 'b', 'c', 'd']

您的问题可以通过以下方式解决:

case('ADD_DEVICE_KEY'): {
    return [
        ...state.slice(0, i),
        {...state[i], likes: [...[state[i].likes], action.payload], // We're creating a new array here which is has the values of state[i].likes and also whatever we add to it
        ...state.slice(i+1)
    ]      

** 编辑 **正如Felix Kling在下面的评论中指出的那样。这实际上是Array Spread Element

州设计

您可能会遇到管理州的问题,将州作为对象存储起来要容易得多。

我们假设您的状态是指用户ID,请考虑更容易引用的方式:

{
    '1234567890': {
        "code": "AAAAAAA",
        "caption": "blah blah blah",
        "likes": [
            "ABCDEFG",
            "BACDEFG"
        ],
        "display_src": "https://pbs.twimg.com/profile_images/1044686525/Get_Some.jpg"
   },
   1234567890: {
        "code": "BBBBBBB",
        "caption": "nah fam",
        "likes": [
            "ABCDEFG",
            "BACDEFG",
            "CBADEFG"
         ],
         "display_src": 'http://got-crossfit.com/wp-content/uploads/2014/04/get-some-rest.jpg'
    }
]

现在,如果你想要使用那些数据,你需要做的只是props[userId]而不是(假设你有一些复杂的逻辑可以在其他地方以一种理智的方式一致地查找i并且可以查找用户; for(const user of props) { if (user.id === userId) return user },第一个更干净,更容易在子组件中进行结构化并且更好阅读。您让JS编译器为您做到这一点,我真的无法想到一个好的将状态存储为数组的原因(特别是考虑到大多数用途的数组只是一个带有数字键的对象)。

通过这样做,您可以使用以下方法轻松添加设备ID:

switch(action.type) {
    case('ADD_DEVICE_ID'): {
        return {
            ...state,
            [action.payload.userId]: Object.assign({}, action.payload.userId, { likes: { deviceId: action.payload.deviceId } })
        }
    }
}

这里我们重新设置返回一个新对象,其余的状态都是相同的,包括除了喜欢的userId对象;现在将deviceId字段设置为我们传入的任何内容。更简洁,更容易合理化方法。

答案 2 :(得分:0)

spread operator(...)Object.assign一起使用可以解决问题

    return 
        [
          ...state.slice(0,i),  // Copy array till index
          Object.assign({},state[i],{likes:state[i].likes+1}),  // update the index array property
          ...state.slice(i+1)   // Copy after the index
        ]