Why is the output of the piece of code below "true"?
class InstagramGallery extends React.Component {
constructor(props) {
super(props);
this.state = {
images: true
};
}
componentDidMount() {
var accessToken = '*Instagram token*';
var instagramApi = new Instagram(accessToken);
instagramApi.userSelfMedia().then(function(result) {
this.setState({
images: false,
});
}, function(err) {
console.log(err);
});
}
render() {
console.log(this.state.images);
return (
<div className="instagram-gallery">
</div>
)
}
}
From what I know, the constructor is being called first. Therefore images=true, after that it renders with console.log(true), and componentDidMount is called. After data from instagram is fetched, and I update component state which should re-render the component with images=false. Where am I wrong?
You are using a regular function for instagramAp.userSelfMedia callback hence losing this context. Use an arrow function instead:
instagramApi.userSelfMedia().then(
result => {
this.setState({
images: false
});
},
function(err) {
console.log(err);
}
);
Regular functions create their own lexical scope, so this does not point your class in the callback function. Arrow functions don't create their own lexical scopes, to this points your component and you can use this.setState().
Using an arrow function saves you from binding your function or keeping this in another variable like:
var accessToken = "*Instagram token*";
var instagramApi = new Instagram(accessToken);
const that = this;
instagramApi.userSelfMedia().then(
function(result) {
that.setState({
images: false
});
},
function(err) {
console.log(err);
}
);
I've not been using RN for that long but does this have an affect?
componentDidMount() {
var accessToken = '*Instagram token*';
var instagramApi = new Instagram(accessToken);
instagramApi.userSelfMedia().then((result) => { //USING ARROW FUNCTION
this.setState({
images: false,
});
}, function(err) {
console.log(err);
});
}
I added an arrow function so that the 'this.state' doesn't get mixed up with the 'this' inside instagramApi.userSelfMedia().
Because this isn’t available
Use arrow function
instagramApi.userSelfMedia().then((result) => {
this.setState({
images: false,
});
}, function(err) {
console.log(err);
});
}
Or bind it manually
instagramApi.userSelfMedia().then(function(result) {
this.setState({
images: false,
});
}.bind(this), function(err) {
console.log(err);
});
}
Related
export class Diet extends Component {
constructor(props) {
super(props);
this.state = {
loaded: false,
Ft: 0,
};
}
async componentDidMount() {
const id = firebase.auth().currentUser.uid;
await firebase.firestore
.collection("users")
.doc(id)
.get()
.then(function (doc) {
if (doc.exists) {
this.setState({
Ft: users.Ft,
});
} else {
alert("error");
}
});
}
Hello, I am trying to retrieve the Ft from my Firestore document and store the value in this.state, so afterward I can use it in an expression later on on the page, any idea on what I'm doing wrong?
Error: [Unhandled promise rejection: TypeError: _firebase.default.firestore.collection is not a function. (In '_firebase.default.firestore.collection("users")', '_firebase.default.firestore.collection' is undefined)]
I think you're looking for
async componentDidMount() {
const id = firebase.auth().currentUser.uid;
firebase.firestore()
.collection("users")
.doc(id)
.get()
.then(function (doc) {
if (doc.exists) {
this.setState({
Ft: doc.data().Ft
});
} else {
alert("error");
}
});
}
You can try consoling your returned data to know what firestore is returning. Another mistake that you're doing is that you're using await together with then/catch and they don't work together in the same function. Run this snippet to correct the mistake and check the console for what firestore is actually returning.
export class Diet extends Component {
constructor(props) {
super(props);
this.state = {
loaded: false,
Ft: 0,
};
}
async componentDidMount() {
const id = firebase.auth().currentUser.uid;
firebase.firestore
.collection("users")
.doc(id)
.get()
.then(function (doc) {
if (doc.exists) {
console.log(doc.data());
//As you're expecting to get Ft then you can set the state like this
this.setState({
Ft: doc.data().Ft
});
} else {
alert("error");
}
});
}}
or use try/catch
export class Diet extends Component {
constructor(props) {
super(props);
this.state = {
loaded: false,
Ft: 0,
};
}
async componentDidMount() {
const id = firebase.auth().currentUser.uid;
let fetchedData = await firebase.firestore.collection("users").doc(id).get()
try {
if(fetchedData.exists){
console.log(fetchedData.data());
//As you're expecting to get Ft then you can set the state like this
this.setState({
Ft: doc.data().Ft
});
}
} catch (error) {
alert("error", error);
}
}
}
I'm new to react and I have a question about a best practice that sees me make a mistake .
I call an API to retrieve information and modify an array in the state once the response is returned by the API. In the "render" I have to retrieve the information from this array (when it is completed) or it sends me back an error because the array is empty when the render is initialized.
class MyClass extends React.Component {
constructor(props) {
super(props)
this.state = {
activeIndex: 0,
items: []
}
}
componentDidMount() {
axios
.get(`API_ADDRESS`, {
headers: {
Authorization: `Token XXX`,
},
})
.then(function(response) {
this.setState({
items: response.results,
})
})
.catch(error => {
notification.warning({
message: error.code,
description: error.message,
})
})
}
changeDialog = (e, index) => {
e.preventDefault()
this.setState({
activeIndex: index,
})
}
render() {
const { activeIndex, items } = this.state
const {
first_name: firstName,
last_name: lastName,
phone,
email,
address,
} = items[activeIndex]
The error indicates :
TypeError: _items$activeInde is undefined
How can I solve this error related to data loading? (trying to keep the destrying elements method)
Thanks a lot
Eliott
Because API that you fetch from server is async. The first time render of Component, data that you setState in axios still not yet updated, it just updated when Component render the second time.
So you must check state in render Component like this to make sure that if activeIndex is defined then declare variable with items[activeIndex] :
activeIndex && const {
first_name: firstName,
last_name: lastName,
phone,
email,
address,
} = items[activeIndex]
Two issues:
beware of this inside the Promise returned by axios. You use function(){} so the this inside is not the component's instance. Change it to an arrow function.
add a guard so you won't destructure undefined when activeIndex points to an item element that is not there (which happens in the initial loading before the axios fetches the data).
Fix:
// ... (code not shown remains unmodified)
componentDidMount() {
axios
.get(`API_ADDRESS`, {
headers: {
Authorization: `Token XXX`,
},
})
.then(response => { // changed this line
this.setState({
items: response.results,
})
})
// ... (code not shown remains unmodified)
render() {
const { activeIndex, items } = this.state
if (!items[activeIndex]) { // added this line
return <div>Hold tight while items are being fetched...</div>; // added this line
} // added this line
const {
first_name: firstName,
// ... (code not shown remains unmodified)
just change your component like so:
constructor(props) {
super(props)
this.state = {
activeIndex: 0,
items: [],
isFetching: false
}
}
componentDidMount() {
// staring your fetching
this.setState({isFetching: true});
axios
.get(`API_ADDRESS`, {
headers: {
Authorization: `Token XXX`,
},
})
.then(function(response) {
// finish fetching when your response is ready :)
this.setState({
items: response.results,
isFetching: false
});
})
.catch(error => {
// finish fetchnig
this.setState({isFetching: false})
notification.warning({
message: error.code,
description: error.message,
})
})
}
changeDialog = (e, index) => {
e.preventDefault()
this.setState({
activeIndex: index,
})
}
render() {
// if your component is while fetching shows a loading to the user
if(this.state.isFetching) return <div>Loading...</div>;
// if there is no results shows a msg to the user
if(this.state.items.length === 0) return <div>there is not items!!!</div>
const { activeIndex, items } = this.state
const {
first_name: firstName,
last_name: lastName,
phone,
email,
address,
} = items[activeIndex]
When I try to use this in my VueJs methods I get the following error
this is undefined
I think that I shouldn't use arrow functions because their this does not bind to the context I expect it to.
I try with a regular function and get the error above.
What I've tried so far
methods: {
connection(){
new elasticsearch.Client({...});
client.search({...})
.then(function (resp) {
var hits = resp.aggregations;
this.tmp = hits[1].value;
}, function (err) {
console.trace(err.message);
});
}
}
I cannot use the this that I want to in the functions passed to .search and .then . How can I have this bind to my VueJs instance so I can access data, computed, etc...?
You should use arrow function to save this context, and don't forget that inside Vue methods this refers to the current instance.
data() {
return {
counter:0,
connections:2,
tmp: 0,
}
},
methods: {
connection() {
// ...
var client = new elasticsearch.Client({
host: 'xxxxxxxxxxxx'
});
client.search({
[...]
}).then((resp) => {
var hits = resp.aggregations;
this.tmp = hits[1].value;
}, (err) => {
console.trace(err.message);
});
}
}
You can assign this variable to local variable(self) and use it in .then function
data () {
return {
counter:0,
connections:2
}
},
methods: {
connection(){
var self = this;
var tmp=0
var elasticsearch = require('elasticsearch');
var client = new elasticsearch.Client({
host: 'xxxxxxxxxxxx'
});
client.search({
"index":"400000",
[...]
}
}).then(function (resp) {
var hits = resp.aggregations;
self.tmp=hits[1].value;
}, function (err) {
console.trace(err.message);
});
console.log("tmp:",tmp)
}
}
I'm at the beginning of making a simple one page photo steam app with the public Flickr stream, but with what i've done so far i'm getting the error
'Cannot set property 'data' of undefined'.
My code:
<b-container>
<b-row>
<b-col>
<p md="4" v-for="photo in Photos">{{photo.id}}</p>
</b-col>
</b-row>
</b-container>
</template>
<script>
import jsonp from "jsonp";
export default {
name: 'PhotoFeed',
data: function() {
return {
Photos: [],
apiURL: "https://api.flickr.com/services/feeds/photos_public.gne?format=json"
}
},
mounted(){
this.getFlickrFeed();
},
methods: {
getFlickrFeed(){
let jsonp = require('jsonp');
jsonp(this.apiURL, {name:'jsonFlickrFeed'}, function(err,data) {
this.data = data;
var self = this;
if (err){
console.log(err.message);
}
else {
this.Photos = self.data;
}
});
}
}
}
</script>
You want var self = this to be outside the anonymous function definition so this keyword is not shadowed by the new function;
getFlickrFeed () {
let jsonp = require('jsonp');
var self = this; // now self refers to the vue component and can
// access the Photos property in data
jsonp(this.apiURL, { name:'jsonFlickrFeed' }, function (err,data) {
if (err){
console.log(err.message);
}
else {
// also use self.Photos to refer to the Vue component
self.Photos = data;
}
});
}
The simplest is to use an arrow function instead of an anonymous function:
jsonp(this.apiURL, { name:'jsonFlickrFeed' }, (err, data) => {
if (err) {
console.log(err.message);
}
else {
this.Photos = data;
}
})
You could use arrow function ()=> and use this in the callback context as follows :
jsonp(this.apiURL, {name:'jsonFlickrFeed'}, (err,data)=> {
this.data = data;
if (err){
console.log(err.message);
}
else {
this.Photos = this.data;
}
});
import getAuthentication from './getAuthentication';
class Home extends React. Component {
constructor() {
super();
//this.authentication = false;
this.state = {
username: '',
password: '',
check:false,
authentication:false
};
this.err = '';
}
componentDidUpdate() {
console.log (this.state.authentication);
console.log(this.state.authentication == true);
if (this.state.check)
{
const promiseAuthentication = getAuthentication(
this.state.username,
this.state.password,
);
promiseAuthentication
.then(response => {
console.log (response.data.Success);
console.log(response.data.Success == true);
this.setState({check :false, authentication:response.data.Success});
})
.catch(error => {
// console.log(error);
this.err = error;
});
}
if (this.state.authentication == true) {
event.preventDefault();
history.push('/overview');
}
}
assignUsername = event => {
this.setState({ username: event.target.value });
};
assignPassword = event => {
this.setState({ password: event.target.value });
};
handleSubmit = () => {
this.setState({ check:true });
};
==============================================================
getAuthentication.js
import axios from 'axios';
function getAuthentication(username, password) {
const authenticationConfig = {
Email: username,
Password: password,
};
return axios.post(
'http://localhost:5002/login/confirmation',
authenticationConfig,
);
}
export default getAuthentication;
In the above code my this.state.Authentication is not getting updated to true
I am trying to update its value in axios promise.
Can someone please tell me what's wrong? I mean I have tried everything but I am not able to proceed.
How do I change the state of Authentication object and switch new window?
I have a second file that is returning the axios promise where promise value is "undefined".. How do I make async call and resolve this issue ??
componentDidUpdate is wrapped in if (this.state.check). Nothing in the code you pasted sets this.state.check to true. Set this.state.check: true.