I am currently using the following to map my array to setState but nothing is getting set and no errors are being logged. If I explicitly write it out line by line, it works. Any thoughts or suggestions on how to go about this?
Set State with Array: (Does not setSate)
const myData = ['message', 'photo', 'isLoggedInhoto'];
const newData = [];
{[...Array(myData.length)].map((x, index) =>
newData.push(myData[index])
)}
this.setState({
newData: localStorage.getItem(newData),
})
Line by line (This works and does setState):
this.setState({
message: localStorage.getItem('message'),
photo: localStorage.getItem('photo'),
isLoggedIn: localStorage.getItem('isLoggedIn')
})
You can't use an array as key of an object and as parameter of getItem
.
You need to loop through newData
and use the computed property name syntax:
newData.forEach(key => this.setState({ [key]: localStorage.getItem(key) }))
Or in refactoring your code, you can achieve it with a single loop and a single setState
call:
const myData = ['message', 'photo', 'isLoggedInhoto']
const newData = {}
{[...Array(myData.length)].map((x, index) =>
newData[myData[index]] = localStorage.getItem(myData[index])
)}
this.setState(newData)
Javascript doesn't deconstruct arrays in the way your code assumes they do, unfortunately. You can't set an array as a key for an object and have it expand to all the items in the array. Your code is simply setting a key named newData
, not setting an array of keys. Javascript keys in object literals don't have to be quoted. This is using the string "newData", not the variable.
For localStorage.getItem()
, the first argument is the string key name. You cannot get multiple keys at once by using an array as the key.
This is a clean way to do it, using ES6 syntax:
this.setState(
[ 'message', 'photo', 'isLoggedInhoto' ].reduce( ( memo, key ) => ({
...memo,
[ key ]: localStorage.getItem( key )
}), {} )
);
Explanation:
We're reducing an array, which sounds like what it does. It reduces all items in the array into one thing. The first argument memo
is the "accumulator", meaning the thing we're reducing to and building on as we go, and the second item is the current element ('message'
, 'photo'
, etc).
An arrow function with this syntax () => ({})
means return an object. Specifically the parenthesis wrapping the curly braces. Without the parenthesis wrapping, as in () => {}
, then anything inside the curly braces is interpreted as a regular function body.
This syntax:
{ ...memo }
Means copy the contents of the old object memo
into a new object. This is the es6 spread operator.
Finally, to set a key based on a variable name, wrap it in []
, as in
{ [ key ]: ... }
So if key is 'message
', it will create an object with { message: ... }
The whole code will produce an object like
{
message: localStorage.getItem('message'),
photo: localStorage.getItem('photo'),
isLoggedIn: localStorage.getItem('isLoggedIn')
}
Which is then passed to setState
so all keys are set correctly.
Additionally, .map()
should not be used in this way in general. .map()
is meant to be used to return a new array with the old values mapped to some new values. Discarding the return from .map()
means you are using the wrong loop paradigm.
[].forEach()
is appropriate for loops that don't return anything and instead have side effects (like pushing to some higher scope array). But in this case neither is ideal, .reduce()
is more semantically correct to produce an object based on an array.
You are trying to create a new state object, with properties from a list, and data extracted from localStorage
using the list as keys.
- Iterate the list using
Array#map
- On each iteration create a new object, with a key from the list, and
get the data from
localStorage
. Don't forget to JSON.parse()
if
you've stored a stringified JSON data,
- Spread the array and create a new object using
Object#assign
.
- Set resulting object to your state.
The code:
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);