(I am using re-base, cant create re-base tag)
I am trying to get user input and then append it onto my state arrays: titles, descriptions and content of a blog and store it in firebase realtime database.
I checked other questions and made sure that my states are arrays so that concat would work.
handleEntry(titleInput, descriptionInput, contentInput) {
this.setState({
titles: this.state.titles.concat(titleInput),
descriptions: this.state.descriptions.concat(descriptionInput),
contents: this.state.contents.concat(contentInput)
})
}
I thought that my state would be updated by instead has a TypeError:this.state.titles.concat is not a function
However, the error points it here at the full stop before syncState:
this.contentsRef = base.syncState('contents', {
context: this,
state: 'contents'
})
UPDATE: I'm not sure if this is the way to do it, but it works. Instead of assigning the state using the state's value, I used a placeholder then assigned it to the state.
handleEntry(titleInput, descriptionInput, contentInput) {
var titleHolder = [...this.state.titles].concat(titleInput);
var descriptionHolder = [...this.state.descriptions].concat(descriptionInput);
var contentHolder = [...this.state.contents].concat(contentInput);
this.setState({
titles: titleHolder,
descriptions: descriptionHolder,
contents: contentHolder
})
}
Related
I'm trying to grab these arrays from one of the nasa open apis -> https://api.nasa.gov/neo/rest/v1/feed?start_date=START_DATE&end_date=END_DATE&api_key=API_KEY
I have a dynamic date in the params so the objects returned match the date, is there any way I can use my date (even though its a string) and turn it into a 'key' value so I can dynamically grab the objects I need?
like => "2021-08-26" would reference { 2021-08-26: [{},{},{}...] }
I have included my code so far with what I've tried, currently I'm trying to just select all the keys inside the {near_earth_objects} using forEach but I'm still getting an error data.near_earth_objects.forEach is not a function
constructor(){
super();
this.state={
asteroids:[],
time: []
}
}
//grab the current time (year-month-day) and store it in the state
componentWillMount(){
var today = new Date();
var start = today.getFullYear()+'-'+0+(today.getMonth()+1)+'-'+today.getDate();
var end = today.getFullYear()+'-'+0+(today.getMonth()+1)+'-'+(today.getDate()+1);
this.setState({time: [start,end]})
}
componentDidMount(){
fetch(`https://api.nasa.gov/neo/rest/v1/feed?start_date=${this.state.time[0]}&end_date=${this.state.time[1]}&api_key=ipAxYzaENbqRKb7GgzFPcH6QUBsHXY3QKB7uXOf5`
)
.then(response => response.json())
.then((data) => {
let asteroids = []
data.near_earth_objects.forEach((arr)=>{
asteroids.push(arr)
})
this.setState({asteroids:asteroids})
});
}
here is an example of the logged data I'm trying to access
It's important to note that the data is coming back as an object where the values are arrays. Since the return data is an object you cannot iterate over it.
However, to get the data you can Object.values(object) (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values) to get an array of the values. This will return something that looks like [ [...], [...] ]
After that you can iterate over this information.
In the end your code should look something like this:
Object.values(data.near_earth_objects).forEach((arr)=>{
asteroids.push(...arr)
})
I have an object:
{ //birthdaysObject
'2000':{
'January':
[{
name: 'Jerry'
},
{
name: 'Chris'
}]
},
'2001':{
'February':
[{
name: 'John'
}]
}
When I go to update the redux store it is replacing the entire year (eg. '2000') object with the new one that I send to my reducer.
How can I push the the nested array of objects without replacing the entire year object?
My reducer currently looks like:
return Object.assign({}, state, {
...state,
birthdays: Object.assign({}, state.birthdays, {
...state.birthdays,
...birthdays
})
});
Where ...birthdays would be another object in the same format as the first code snippet.
I am also open to suggestions about the structure of my data, normalizing, etc.
Any help would be appreciated.
The object keys in the birthdaysObject are unknown and are assigned when iterating through a separate object. I've tried kolodny/immutability-helper however the $merge function is returning the same results as what my reducer is already doing.
I had the same problem some time ago.
Follow the way I done it.
You have an object, but I think you should have an array of objects.
I also have different names on variables, but this should not be a problem to understand the logic
//do a copy of the array first
let newSubscriptions = state.customer.master.subscriptions.slice();
//for the value you want to change, find it's position in the array first
const indexInSubscriptions = newSubscriptions.map(function(item) {
return item.id;
}).indexOf( action.id);
//get the child you want to edit and keep it in a new variable
const under_edit_subscription = state.customer.master.subscriptions[indexInSubscriptions];
//go again over the array and where is the value at the index find above, replace the value
newSubscriptions = newSubscriptions.map((item, i) =>
i === indexInSubscriptions ? under_edit_subscription : item
)
//add the whole array into the state
return {
...state,
customer: {
...state.customer,
master: {
...state.customer.master,
subscriptions : newSubscriptions
}
}
}
This is what I have so far: https://gist.github.com/justgoof9/f6250cdbd615bda139ef8d56375fa12c
So when I add items to the list then when I refresh the browser, I want it to still save. I want to do it with JSON but don't know how. Can anyone help me?
Yes you can achieve it by using local storage, so whenever you push something to your to Todo list, save the updated list in local storage and then when you are rendering in the UI use the data that is stored in local storage. Here is a small example to achieve this --> https://www.w3schools.com/html/html5_webstorage.asp
Hope this solved your problem.
Hi storing objects in LocalStorage is a bit tricky because LocalStorage accepts strings, but JSON.stringify() comes to the rescue! In you function addToList:
addToList = input => {
let listArray = this.state.lists;
listArray.push(input);
this.setState({
list: listArray,
userInput: ""
});
};
You want to add a LocalStorage call that saves the list from this.state into LocalStorage, like this:
addToList = input => {
let listArray = this.state.lists;
listArray.push(input);
this.setState({
lists: listArray,
userInput: ""
}, () => {
window.localStorage.setItem('savedList', JSON.stringify(this.state.lists));
});
};
And to retrieve it, you need to parse it back into an array/object, like this:
componentDidMount() {
const list = window.localStorage.getItem('savedList');
const parsedList = JSON.parse(list);
this.setState({
lists: parsedList,
})
}
Now every new item you add is saved to localStorage and is retrieved on refresh, all that is left is to apply the same logic to removing items, like this:
listOnClick = index => {
var arr = this.state.lists;
arr.splice(index, 1);
this.setState({ lists: arr }, () => {
window.localStorage.setItem('savedList', JSON.stringify(this.state.lists));
});
};
You also had a typo in addToList, you were assigning to this.state.list instead of this.state.lists
So, I have a a state of users which gets filled up with an array of Objects from the backend. Say, I want to update the details of a specific User Object from that array and then update the current state with the updated details. How do I go about doing that?
What I currently do is force a refetch from the server once the update request is successful to update the state again but I was wondering if there's a better way to do it without refetching from the server again.
For example, on the code below. I wanted to update PersonTwo's age.
state = {
users: [
{
name: PersonOne,
age: 1
},
{
name: PersonTwo,
age: 1
}
]
}
Let's say you have id field in your object. You can use map function to return new array and save it to your state.
updateUser(userId){
const updatedUsers = this.state.users.map( (user) => {
if(userId !== user.id) {
return user;
}
return {
...user,
//write some updated info here, for example:
age: 40
}
}):
this.setState({
users: updatedUsers
});
});
The best way is to do as you are doing right now that first send the values to the server and then fetch the latest data from the database because if you update the view before successful update on the server you might end up showing which does not exist actually. There is a possibility that your server did not accept that change but somehow you updated the view on user request. It is not a good thing, but if you still want to do that follow the steps below:
step-1: check the array index on which the update of user data is done and then
const newArray = Array.from(this.state.oldArray);
newArray[i] = 'test';
step-2: assign this new array to the old one:
this.setState({oldArray: newArray})
You can use functional setState as a success callback of POST/PUT call.
this.setState(prevState => {
users: ... // operation using prevState.users
})
I am new to both React and Firebase. I struggled a bit to get data from the database, even though the instructions on the Firebase website were pretty straightforward.
I managed to print data in the view by using this code:
Get data from DB and save it in state:
INSTRUMENTS_DB.once('value').then(function(snapshot) {
this.state.instruments.push(snapshot.val());
this.setState({
instruments: this.state.instruments
});
From Firebase, I receive and Object containing several objects, which correspond to the differen instruments, like shown in the following snippet:
Object {
Object {
name: "Electric guitar",
image: "img/guitar.svg"
}
Object {
name: "Bass guitar",
image: "img/bass.svg"
}
// and so on..
}
Currently, I print data by populating an array like this:
var rows = [];
for (var obj in this.state.instruments[0]) {
rows.push(<Instrument name={this.state.instruments[0][obj].name}
image={this.state.instruments[0][obj].image}/>);
}
I feel like there's a better way to do it, can somedody give a hint? Thanks
I user firebase a lot and mu solution is little ES6 helper function
const toArray = function (firebaseObj) {
return Object.keys(firebaseObj).map((key)=> {
return Object.assign(firebaseObj[key], {key});
})
};
I also assign the firebase key to object key property, so later I can work with the keys.
The native map function only works for arrays, so using directly it on this object won't work.
What you can do instead is:
Call the map function on the keys of your object using Object.keys():
getInstrumentRows() {
const instruments = this.state.instruments;
Object.keys(instruments).map((key, index) => {
let instrument = instruments[key];
// You can now use instrument.name and instrument.image
return <Instrument name={instrument.name} image={instrument.image}/>
});
}
Alternatively, you can also import the lodash library and use its map method which would allow you to refactor the above code into:
getInstrumentRowsUsingLodash() {
const instruments = this.state.instruments;
_.map(instruments, (key, index) => {
let instrument = instruments[key];
// You can now use instrument.name and instrument.image
return <Instrument name={instrument.name} image={instrument.image}/>
});
}
Side note:
When you retrieve you data from Firebase you attempt to update the state directly with a call on this.state.instruments. The state in React should be treated as Immutable and should not be mutated with direct calls to it like push.
I would use map function:
_getInstrumentRows() {
const instruments = this.state.instruments[0];
if (instruments) {
return instruments.map((instrument) =>
<Instrument name={instrument.name}
image={instrument.image}/>);
}
}
In your render() method you just use {_getInstrumentRows()} wherever you need it.