For some reason, I am unable to update the state of my component with the data from my fetch request.
When I console.log, I can see that I am getting the data. I'm not sure what this could be
If this is a noob issue, please bear with me. I'm still learning.
Here is my code:
import React, { Component } from "react";
class Nav extends Component {
state = {
searchTerm: "",
posts: []
};
getPost = e => {
e.preventDefault();
const val = e.target.value;
this.setState({ searchTerm: val }, () => {
if (val !== "") {
fetch(
`http://www.reddit.com/search.json?q=${val}&sort=relevance&limit=25`
)
.then(res => res.json())
.then(data => console.log(data.data))
//.then(data => this.setState({ posts: data.data }))
//.then(console.log(this.state.posts))
.catch(err => console.log(err));
}
});
};
Actually everything is right and going well, just your logging is wrong.
.then(console.log(this.state.posts))
That logs the state now and passes the result of console.log() (undefined) to the .then chain as a callback which is obviously wrong. I guess you meant:
.then(() => console.log(this.state.posts))
But that still won't work as setState does not trigger a state update immeadiately, but somewhen. After that it calls the second argument as a callback, so you should log then:
.then(data => this.setState({ posts: data.data }, () => {
console.log(this.state.posts);
}))
Altogether:
const response = fetch(
`http://www.reddit.com/search.json?q=${val}&sort=relevance&limit=25`
).then(res => res.json());
// PS: I would not build up a chain if the logic is not really "chained"
response.then(data => console.log(data.data));
response.then(data => this.setState({ posts: data.data }, () => console.log(this.state.data)));
response.catch(err => console.log(err));
Related
For my project, I have to get several APIs in my projects, these APIs are linked to the others, i.e. they have the same data ...
Here is my code
export default class App extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
Promise.all([
getData(),
getData('?page=2'),
])
.then(([dataSource1, dataSource2]) => {
this.setState({
isLoading: false,
isLoading2: false,
dataSource1,
dataSource2,
});
})
.catch((error) => {
// handle errors
});
}
render() {
const getData = (subpath = '') => fetch(`https://api.rawg.io/api/games${subpath}`)
.then(res => res.json())
.then(result => result.results);
console.log(getData)
}
I tried with axios but without success ...
When I remove the comment, it shows me only the second fetch ...
You need two separate fetch calls for each API. To wait for both to finish, use Promise.all.
const getData = (subpath = '') => fetch(`https://api.rawg.io/api/games${subpath}`)
.then(res => res.json())
.then(result => result.results);
componentDidMount() {
Promise.all([
getData(),
getData('?page=2'),
])
.then(([dataSource1, dataSource2]) => {
this.setState({
isLoading: false,
isLoading2: false,
dataSource1,
dataSource2,
});
})
.catch((error) => {
// handle errors
});
}
I need help doing this. I want to save the user list from the API to an array (called "name"). How can I do this? I tried this forEach but can't make it work. Thanks!
Edit: I wraped the function, still not working.
import axios from 'axios'
export default {
data () {
return {
info: null,
name: []
}
},
mounted () {
axios
.get('http://localhost:3000/api/users/', {mode: 'no-cors'})
.then(response => (this.info = response.data))
.then(() => info.data.forEach(element => {
}))
.catch(error => {
console.log(error)
this.errored = true
})
.finally(this.loading = false)
}
}
From the code above I'm assuming the data in this.info in correct. The problems I see in your code are:
1.
.then(response => (this.info = response.data))
.then(() => info.data.forEach(element => {
}))
info looks to be undefined. I assume this should be this.info.
.then(response => (this.info = response.data))
.then(() => this.info.data.forEach(element => {
}))
Or if you're using the arrow function syntax and returning an assignment expression, you can use
.then(response => (this.info = response.data))
.then(info => info.data.forEach(element => {
}))
Which I don't really recommend, since some linting rules disallow returning assignment expressions (for good reasons). To chain a promise that relies on this implicit language behavior can make code less easily understood.
2.
What forEach does matters. Vue's reactivity does not pick up certain assignment syntax, i.e. this.name[i] = element. You can use array methods like push, but I recommend you use functional programming operators, like map and filter:
.then(() => (this.name = this.info.data.map(element => {
})))
Maybe the this reference is not correct, because on callback methods is on another context, try it:
export default {
data () {
return {
info: null,
name: []
}
},
mounted () {
var self = this
axios
.get('http://localhost:3000/api/users/', {mode: 'no-cors'})
.then(response => (self.info = response.data))
.then(info.data.forEach(element => {
});)
.catch(error => {
console.log(error)
this.errored = true
})
.finally(this.loading = false)
}
}
you forgot to encapsulate the callback into a function receiving the info variable,
try this:
import axios from 'axios'
export default {
data () {
return {
info: null,
name: []
}
},
mounted () {
axios
.get('http://localhost:3000/api/users/', {mode: 'no-cors'})
.then((response) => response.data.forEach(element => {
}))
.catch(error => {
console.log(error)
this.errored = true
})
.finally(this.loading = false)
}
}
I have the below code, where I have to get data from all the files in the same DB. Node.js is running at the backend. When I try the below code, I always get the last fetch, can anyone please help me how to fix this.
The below is from the react JS frontend.
componentDidMount() {
console.log("This Worked Sucessfully")
this.getDataFromDb();
if (!this.state.intervalIsSet) {
let interval = setInterval(this.getDataFromDb, 1000);
this.setState({ intervalIsSet: interval });
}
}
getDataFromDb = () => {fetch('http://172.24.78.202:3001/api/passed')
.then(data => data.json())
.then(res => this.setState({ passed: res.data }));
};
getDataFromDb = () => {fetch('http://172.24.78.202:3001/api/failed')
.then(data => data.json())
.then(res => this.setState({ failed: res.data }));
};
getDataFromDb = () => {fetch('http://172.24.78.202:3001/api/all')
.then(data => data.json())
.then(res => this.setState({ data2: res.data }));
};
render() {
const primaryColor = getColor('primary');
const secondaryColor = getColor('secondary');
const { passed, failed, data2 } = this.state
From what I see by your code, you seem to be re-writing your goGetDataFromDB two times. Try changing the names of each function or, the way you call them. You can also take advantage of Promise.all to group the results of each call into a single return handle.
Check this link for the documentation of Promise.all
You could refactor your current code to something like this:
class MyComponent extends React.Component {
componentDidMount() {
this.getDataFromDb();
if (!this.state.intervalIsSet) {
let interval = setInterval(this.getDataFromDb, 1000)
this.setState({intervalIsSet: true })
}
}
getDataFromDb = () => {
Promise.all([
'http://172.24.78.202:3001/api/passed',
'http://172.24.78.202:3001/api/failed',
'http://172.24.78.202:3001/api/all'
].map(url => (
fetch(url)
.then(data => data.json())
.then(res => res.data)
)
)).then(([passed, failed, data2]) =>
this.setState({ passed, failed, data2 })
);
}
render() {
//...
}
}
I tried to keep as much as your code as possible so you could notice the differences.
I hope this helps.
Not sure what i'm tyring to do is possible, but
state = {
characters: [],
planets: [],
search: "",
selectedCharacter: null
};
componentDidMount() {
this.fetchSomeData(
"https://rickandmortyapi.com/api/character/",
"characters"
);
this.fetchSomeData("https://rickandmortyapi.com/api/location", "planets");
}
fetchSomeData = (url, stateToSet) => {
fetch(url)
.then(res => res.json())
.then(data => this.setState({
[stateToSet]: data.results,
next: data.info.next,
prev: data.info.prev
}))
.catch(err => alert(err));
};
I have a characters page, and a planets page both obviously 2 different endpoints from the api
https://rickandmortyapi.com/api/character/
https://rickandmortyapi.com/api/location/
the problem i'm having:
when
componentDidMount(){
}
runs it's fetching both sets of data, then storing both
next page endpoints in the next state
"https://rickandmortyapi.com/api/location/?page=2"
"https://rickandmortyapi.com/api/character/?page=2",
i need to access next when clicking a button to reload the next page of data. (one component displays characters, for that one i need the "https://rickandmortyapi.com/api/character/?page=2",
and one component displays planets for that one i need "https://rickandmortyapi.com/api/character/?page=2",
)
how can i store these 2 separately?
i was thinking of trying to match them to their respective endpoints like this:
fetchSomeData = (url, stateToSet) => {
fetch(url)
.then(res => res.json())
.then(data => this.setState({
[stateToSet]: data.results,
**[stateToSet]next: data.info.next,**
prev: data.info.prev
}))
.catch(err => alert(err));
};
but i'm not sure you can incorporate the parameter into it like that.
You need to change a small thing in fetchSomeData like below:
fetchSomeData = (url, stateToSet) => {
fetch(url)
.then(res => res.json())
.then(data => this.setState({
[stateToSet]: data.results,
[`${stateToSet}-next`]: data.info.next,
[`${stateToSet}-prev`]: data.info.prev
}))
.catch(err => alert(err));
};
used [${stateToSet}-next] Template literals. Hope it helps and demo
This will print :
{
characters: Array[20],
characters-next: "https://rickandmortyapi.com/api/character/?page=2"
characters-prev: ""
planets: Array[20],
planets-next: "https://rickandmortyapi.com/api/location?page=2"
planets-prev: ""
search: "",
selectedCharacter: ""
}
and #Croolsby's answer also nice solution.
This should do it:
fetchSomeData = (url, stateToSet) => {
fetch(url)
.then(res => res.json())
.then(data => this.setState({
[stateToSet]: {
results: data.results,
next: data.info.next,
prev: data.info.prev
}
}))
.catch(err => alert(err));
};
Then you can access it like this:
this.state.characters.next
this.state.planets.next
The general lesson here is that you can have nested objects inside this.state.
Full error image:
error image
I am making a fetch request and when I want to set the state to save some errors that happens. How do I fix this?
Code:
onClickLogIn = (username, password) => {
const request = fetch('[SOMEAPILINK]', {
method: 'POST',
headers: {
Accept: 'text/javascript',
'Content-Type': 'text/javascript',
},
body: JSON.stringify({
username: username,
password: password,
login: 1
})
}).then(response => response.json()).then(responseJson => {
console.log(responseJson)
this.setState({
errorCheck: responseJson.error
})
}).catch(error => {
console.log("error")
})
// console.log(errorCheck);
console.log(request);
console.log("----ERROR CHECK ----")
console.log(this.state.errorCheck)
this.props.navigation.navigate("Second")
}
So when I want to set errorCheck that error comes in...
Thanks!
then(response => response.json()).then(responseJson => {
console.log(responseJson)
this.setState({
errorCheck: responseJson.error
})
this.props.navigation.navigate("Second")
})
=> Add this code this.props.navigation.navigate("Second") of navigation inside the then() method so it will call navigation after updating the state then your error will gone.
=> and try to update the state using setState function not an object so try
this.setState(function (prevState, props) {
return { errorCheck: responseJson.error}
})
it will reduce the time , taken by the object to update the state.
=> So your code will look like
then(response => response.json()).then(responseJson => {
console.log(responseJson)
this.setState(function (prevState, props) {
return { errorCheck: responseJson.error}
})
this.props.navigation.navigate("Second")
})
setState is asynchronous. So if you unmount the stateful component (by calling navigate) before updating the state then you'll get the warning.
You should use the callback that setState provides instead
.then(response => response.json()).then(responseJson => {
console.log(responseJson)
this.setState({
errorCheck: responseJson.error
}, () => {
this.props.navigation.navigate("Second")
})
})