【问题标题】:How to use an array with setState?如何使用带有 setState 的数组?
【发布时间】:2017-04-29 02:31:55
【问题描述】:

我目前正在使用以下方法将我的数组映射到 setState,但没有设置任何内容,也没有记录任何错误。如果我逐行明确地写出来,它就可以工作。关于如何解决这个问题有什么想法或建议吗?

用数组设置状态:(不设置状态)

const myData = ['message', 'photo', 'isLoggedInhoto'];
const newData = [];

{[...Array(myData.length)].map((x, index) =>
  newData.push(myData[index])
)}

this.setState({
  newData: localStorage.getItem(newData),
})

逐行(这有效并且确实 setState):

this.setState({
  message: localStorage.getItem('message'),
  photo: localStorage.getItem('photo'),
  isLoggedIn: localStorage.getItem('isLoggedIn')
})

【问题讨论】:

  • 这里有很多问题。 getItem 接受一个字符串,而不是一个对象。您还没有将 newData 设置为 localStorage。你还想完成什么?您可以使用 myData.slice() 或 es6 中的 [...myData] 克隆数组
  • 我明白了。您的目标是根据名称使用来自本地存储的一组项目来设置状态
  • 数据正在构造函数中设置...问题,是的。因此问题

标签: javascript arrays reactjs ecmascript-6 state


【解决方案1】:

不幸的是,Javascript 不会像您的代码假设的那样解构数组。您不能将数组设置为对象的键并将其扩展到数组中的所有项目。您的代码只是设置一个名为newData 的键,而不是设置键数组。对象文字中的 Javascript 键不必被引用。这是使用字符串“newData”,而不是变量。

对于localStorage.getItem(),第一个参数是字符串键名。使用数组作为键不能一次获取多个键。

这是一种简洁的方式,使用 ES6 语法:

this.setState(
    [ 'message', 'photo', 'isLoggedInhoto' ].reduce( ( memo, key ) => ({
        ...memo,
        [ key ]: localStorage.getItem( key )
    }), {} )
);

解释:

我们正在减少一个数组,听起来就像它所做的那样。它将数组中的所有项目简化为一件事。第一个参数memo 是“累加器”,意思是我们正在减少和构建的东西,第二个参数是当前元素('message''photo' 等)。

具有这种语法() => ({}) 的箭头函数表示返回一个对象。特别是包裹花括号的括号。如果没有括号包装,如() => {},那么花括号内的任何内容都将被解释为常规函数体。

这个语法:

{ ...memo }

表示将旧对象memo 的内容复制到新对象中。这是 es6 扩展运算符。

最后,要根据变量名设置一个键,把它包装在[]中,如

{ [ key ]: ... }

所以如果key是'message',它将创建一个带有{ message: ... }的对象

整个代码会产生一个类似的对象

{
    message: localStorage.getItem('message'),
    photo: localStorage.getItem('photo'),
    isLoggedIn: localStorage.getItem('isLoggedIn')
}

然后将其传递给setState,以便正确设置所有键。

此外,.map() 通常不应以这种方式使用。 .map() 用于返回一个新数组,其中旧值映射到一些新值。丢弃来自.map() 的返回意味着您使用了错误的循环范例。

[].forEach() 适用于不返回任何内容但有副作用的循环(例如推送到更高范围的数组)。但在这种情况下,两者都不理想,.reduce() 在语义上更正确,可以基于数组生成对象。

【讨论】:

  • 谢谢,安迪也可以!只有一周的反应和 es6...:)
  • 这个答案在语义上更正确,不会多次调用 setState。更短并不总是更好;)
【解决方案2】:

您正在尝试创建一个新的状态对象,其属性来自列表,并使用列表作为键从localStorage 中提取数据。

  1. 使用Array#map 迭代列表
  2. 在每次迭代中,使用列表中的键创建一个新对象,然后 从localStorage 获取数据。不要忘记JSON.parse() 如果 你已经存储了一个字符串化的 JSON 数据,
  3. Spread 数组并使用Object#assign 创建一个新对象。
  4. 将结果对象设置为您的状态。

代码:

const myData = ['message', 'photo', 'isLoggedInhoto'];
const state = Object.assign({}, ...myData.map((prop) => ({
  [prop]: localStorage.getItem(prop) // or JSON.parse(localStorage.getItem(prop)) if your storing a JSON
})));

this.setState(state);

【讨论】:

  • 感谢 Ori,但收到此控制台错误。 “JSON 中位置 0(...) 的意外标记 W”
  • 您没有存储非 JSON 数据,所以 JSON.parse() 无法解析。删除JSON.parse() 即可。
  • 我在答案中将JSON.parse() 设为可选。
  • 检查 JSON.stringify() JSON.parse() 做了什么。您将需要它们来在 localStorage 中存储对象和数组,或使用 AJAX 调用发送它们。
【解决方案3】:

您不能将数组用作对象的键和getItem 的参数。

您需要遍历newData 并使用computed property name 语法:

newData.forEach(key => this.setState({ [key]: localStorage.getItem(key) }))

或者在重构你的代码时,你可以通过一个循环和一个setState调用来实现它:

const myData = ['message', 'photo', 'isLoggedInhoto']
const newData = {}

{[...Array(myData.length)].map((x, index) =>
  newData[myData[index]] = localStorage.getItem(myData[index])
)}

 this.setState(newData)

【讨论】:

  • 他们都工作了。我选择了 ---- const myData = ['message', 'photo', 'isLoggedIn']; myData.forEach(key => this.setState({ [key]: localStorage.getItem(key) })) -- 成功了,谢谢GG!!
猜你喜欢
  • 2017-03-23
  • 1970-01-01
  • 2020-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-17
  • 2023-01-09
相关资源
最近更新 更多