This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 3 years ago.
I'm trying to wait for data in componentDidMount and then change my state isLoading to false but setState is not triggering. I'm able to console.log the data inside branch.init but I don't know why setState is not working.
state = {
isLoading: true,
}
componentDidMount() {
console.log("componentDidMount");
let branchKeyTest = 'key_test_aBcDeF'
branch.init(branchKeyTest, function(err, data) {
console.log(JSON.stringify(data, null, 1))
this.setState({ isLoading: false })
if (data && data.data_parsed) {
switch (data.data_parsed.link_type) {
case 'new_release':
localStorage.setItem('redirect', JSON.stringify({
'link_type': 'new_release',
'release_id': data.data_parsed.release_id
}));
break;
default:
console.log("do nothing")
}
}
})
}
render() {
const { isLoading } = this.state;
if (!isLoading) {
return (
<div>Done Loading</div>
)
else {
return (
<div>Still Loading</div>
)
}
}
branch.init(branchKeyTest, function(err, data) { needs to be changed to branch.init(branchKeyTest, (err, data) => { because you don't have access to the class's this keyword inside the anonymous function.
The way you wrote it, you don't have access to this because this was referring to the function's context - not the class. By changing it to fat arrow syntax, you can access this for the React class's context.
You can read more about this here.
Related
I have a constructor, get method, componentDidMount and componentWillUnmount methods. I want to just listen for a scroll event and, according to that, call the get method. If the scroll is at the bottom of page, the get method is called one time. That's all. The first call, that is componentDidmount(), is working one time but when I scroll down, the get method is working two times. I don't want it to execute more than once.
This is my code:
constructor(props) {
super(props);
cursor = -1
id = auth().currentUser.providerData[0].uid
this.state = {
hits: [],
isLoading: false,
over: false,
firstCall: true
};
this.get = this.get.bind(this)
this.handleScroll = this.handleScroll.bind(this)
}
get() {
this.setState({ isLoading: true });
fetch("/1.1/followers/list.json?user_id=" + id + "&cursor=" + cursor + "", {
headers: {
'Authorization': 'MyToken',
}
}).then(response => response.json())
.then(data => {
if (data.next_cursor == 0) {
this.setState({ isLoading: false })
this.setState({ over: true })
} else {
this.setState({ hits: this.state.hits.concat(data.users), isLoading: false })
cursor = data.next_cursor
console.log(data.next_cursor)
}
}).catch(error => {
return
})
}
componentDidMount() {
this.get()
window.addEventListener('scroll', this.handleScroll);
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll);
}
handleScroll(event) {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
this.get()
}
}
And that is my console output.
1634251341094964000 ----> one time
1614497980820334000 ----> two time
1579177573029464600 ----> two time
.
.
.
They are coming from console.log(data.next_cursor) at the get function.
Since it seems like the event gets fired multiple times by the window / scrollbar, you'll need to guard against duplicate calls in your code. There are many ways to do this, depending on the context and the requirements. Here are a couple options.
You could debounce the function call. This would be good if you just need to make sure it is only called once within a certain time window.
Another option is to use state, and theisLoading prop you've already defined:
get(){
if(!this.state.isLoading){
//use the setState callback param here so we don't run into async issues
this.setState({isLoading: true}, () => {
... the rest of your logic ...
//get is finished (either success or failure)
this.setState({isLoading: false});
}
}
}
I am trying to be able to read a value that is boolean to see if a user did a specific action or not and I am using the ReactJS functional component style. I am trying to read the runValue in my code to see if the run() method changed the value and I want to be able to read this value without recalling the function.
I want to be able to put in my useEffect method this line of code;
Run.RunFunction().run((index) => {
if (index) {
\\\ do stuff here if index is true
} else {
///if index is false
}
}
my code
const Run = {
RunFunction: () => {
let runValue = false;
return {
run() {
runValue = true
},
listener: function(val) {},
checkStatus: function(listen) {
this.listener = listen
}
}
},
}
Run.RunFunction().checkStatus((index) => {
if (index) {
console.log('running')
} else {
console.log('not running')
}
});
I am having trouble having this code to work and I want to be able to see the value of the runValue initially and if it changes.
Thank you
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 3 years ago.
I am getting this weird issue in facebook login where I get the response but after getting the response, I am not able to dispatch actions.
Therefore, I wrote a function to do this but I am getting this.setData is not a function.
testAPI() {
window.FB.api('/me' ,function(response) {
console.log("testAPI",response);
if(response){
userProfile = {
access_token:accessToken,
id:response.id,
name:response.name,
provider: "Facebook",
};
console.log("userProfile",userProfile);
this.setData(userProfile);
}
console.log('[FacebookLoginButton] Successful login for: ', response);
});
}
setData = userProfile => {
this.setState(
{
userData: userProfile
},
() => {
console.log("inside setData");
if (userProfile !== undefined) {
console.log("inside callback", userProfile);
this.props.loginUser(this.state.userData);
}
}
);
};
This will help ( https://medium.freecodecamp.org/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56 ) [ You need to bind function in order to set context of this ]
You have to use arrow function, or bind function to set correct context of this.
window.FB.api('/me', response => {
// function body
}
An API call (Firebase) determines the return value of my computed property and hence whether I display certain elements in my template.
Yet, my computed property is actually not reactive: its value in my template doesn't change upon the API call. Why not?
JS:
myComputedProperty: function() {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
return true;
}
else {
return false;
}
});
}
Template:
<span v-if="userConnected">
User connected
</span>
Your return value isn't the return value for your computed property. It's the return value of the callback function.
You should be using data() and created() or mounted() to check this instead:
data () {
return {
isAuthenticated: false
};
},
created () {
firebase.auth().onAuthStateChanged((user) => {
this.isAuthenticated = !!user
});
}
Here a simplified version of a React component I have:
class Example extends Component {
constructor(props) {
super(props);
this.state = {key : 10 };
this.value = null;
}
componentDidMount() {
this.fetchValueFromServer();
this.fetchSecondValueFromServer();
}
fetchValueFromServer() {
fetch_value_from_server(this.state.key).then( (value) => {
this.value = value;
});
}
fetchSecondValueFromServer() {
is_ready(this.value).then(() => {
console.log("there");
});
}
}
I expect to see the console.log("there") printed but this.value always remains null, even thou is set in the fetchValueFromServer. Why is this?
if you are curious to how is_ready looks it's a simple promise:
function is_ready(variable) {
return new Promise((resolve, reject) => {
let interval = setInterval(() =>
{
if (variable) {
clearInterval(interval);
resolve();
}
}, 100);
});
}
The problem is with the logic of the is_ready function. It looks like you want that function to repeatedly check if that value is there, then resolve when it is. However, because of how closures in JS work, that variable argument will only ever have one value in the context of that function's body, even after this.value changes. Look at this small example:
let secret = 'not found yet'
function checkSecret(secretArg) {
setInterval(() => {
console.log(secretArg)
}, 500)
}
checkSecret(secret)
setTimeout(() => { secret = 'secret found!' }, 1000)
This code will always print 'not found yet', because it's checking the secretArg variable that's been assigned locally, and not the secret variable directly.
Looks like you need to resolve with the variable value within the function is_ready, like so:
resolve(variable);
Then add a param to your console log to determine more, like so:
fetchSecondValueFromServer() {
is_ready(this.value).then((returnValue) => {
console.log("there", returnValue);
});
}
figured it, the value in is_ready is passed by value! Javascript needs to implement & so we can pass crap by ref!