How we can call react set state from Sync callback function for example
MyClass.getAynchFunction(inputParam, function (err, data) {
if (err) console.log(err, err.stack); // an error occurred
else {
console.log(JSON.stringify(data))
}
}
I want to set variable from 'data' object in react component state.
It's a bit of a guess because you're not specifying what exactly doesn't work, but I'm guessing you're getting something like this.setState is not a function.
That's because this isn't the React component inside your callback function. There's basically two ways to fix this
// Bind the current this to the callback function.
MyClass.getAyncFunction(
"input",
function(err, data) {
this.setState({ responseData: data });
}.bind(this)
);
// Rewrite it as an arrow function so the current this is automatically bound.
MyClass.getAyncFunction("inputParams", (err, data) => {
this.setState({ responseData: data });
});
I would go with the arrow function because it's cleaner.
Related
I'm trying to authenticate the user using the google. Everything is going fine. But when I try to console.log(this) inside of the onAuthStateChanged() is printing something like
Object { next: componentDidMount(user), error: noop(), complete: noop()
}
complete: function noop()
error: function noop()
next: function componentDidMount(user)
<prototype>: Object { … }
But if I console.log(this) outside of the onAuthStateChanged() its working fine with the information of the current class.
What I want is, I want to update the state information with the user details by using this this.setState() method. But this.setState() method is not working inside of the onAuthStateChanged().
How can I do it?
Here is my code
componentDidMount = ()=>{
console.log(this)
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
console.log(this)
console.log("userSignedIn")
} else {
console.log(" No user is signed in.");
}
});
};
The problem is that this has a different meaning inside the callback, due to how you declare it.
The simplest fix is to use a fat arrow to declare the callback, same as you do elsewhere:
componentDidMount = ()=>{
console.log(this)
firebase.auth().onAuthStateChanged((user) => { // 👈
if (user) {
console.log(this)
console.log("userSignedIn")
} else {
console.log(" No user is signed in.");
}
});
This is an incredibly common problem, so I recommend reading more on it here: How to access the correct `this` inside a callback?
I'm currently using functions to predefine all of my axios calls so for example:
export const getClients = () => {
axios.get("/client/")
.then(response=>{
return response;
})
.catch(error=>{
return error;
});
};
Now, I want to call this in a class-based component in the componentDidMount like this:
componentDidMount(){
this.setState({
clients: getClients()
});
}
I can't seem to figure out why when I try to console.log(this.state.clients) at the end of componentDidMount I'm getting an undefined error. I'm new to React and from what I understand, the then in the function of the axios call should resolve the promise and return the actual response from the API call so when I call getClients(), the clients state should be the response.
What am I doing wrong?
componentDidMount(){
fetchClients();
}
const fetchClients = () => {
getClients().then( (response)=> {
// handle success
this.setState({clients:response});
});
};
Okay there is some stuff that needs to be cleared out here :-
You need to change getClients like so :-
export const getClients = () => {
return axios.get("/client/")
.then(response=>{
return response;
})
.catch(error=>{
return error;
});
};
Why ?
Because the value that you returned from the callback of then is wrapped inside a Promise implicitly and has to be returned for consumption as you do in a function like function sum(a,b) {return a+b}
componentDidMount will change like so :-
componentDidMount(){
const fetchClients = async () => {
const clients = await getClients();
this.setState({clients});
}
fetchClients();
}
Why ?
If you want to use getClients in a statement fashion instead of .then().then() promise chain, you will first wrap it inside an async function and then call await on getClients() (remember this function returns a Promise) and then set the state inside that async function.
Even if you console.log the clients state after fetchClients() within componentDidMount, you probably won't see the value set because setState works asynchronously. So never rely on the console.log of your state just after setting it.
how to remove lag in setState using callback function in react
tried using callback but still lag state and data in array state cannot be mapped
mapfn(){
ServerAddr.get(`/dishes/read/meal/category`)
.then(res => {
const getmeal6 = res['data']['data'];
this.setState({ getmeal6 },()=>{
console.log('log233',this.state.getmeal6);
});
});
console.log('log232',this.state.getmeal6);
this.state.getmeal6.map((item) => {
return (
this.setState({
maparr:[...this.state.maparr,item.id],
})
);
});
console.log(this.state.maparr,'val32');
}```
in log233 the state is proper but in log232 the state lags with 1
The problem with your current code is that both http calls, and calls to setState are asynchronous.
// this call is asynchronous
ServerAddr.get(`/dishes/read/meal/category`)
.then(res => {
const getmeal6 = res['data']['data'];
// this is also asynchronous
this.setState({ getmeal6 },()=>{
});
});
// this call happens synchronously! It will almost certainly happen before the two
// async calls complete
this.state.getmeal6.map((item) => {
return (
this.setState({
maparr:[...this.state.maparr,item.id],
})
);
});
If you want to do something after your http call and the setState are both resolved, you need to either be inside the then function of a promise, or in the callback function of setState.
So something like this:
// this call is asynchronous
ServerAddr.get(`/dishes/read/meal/category`)
.then(res => {
const getmeal6 = res['data']['data'];
// this is also asynchronous
this.setState({ getmeal6 },()=>{
// this is where you need to put the
// code you want to happen after the http call and setState
});
});
That said, you need to reconsider what you are trying to do - either by refactoring your state management using something like Redux, or by using async await in your method, to make your code a little easier to read, or by a totally new approach to the problem at hand.
I have to call API when the user stops typing and it is working perfectly fine. And I have to mount when the enter key is pressed.
I made a Mock Component here which does this.
But, when the component is unmounted it shows the error Cannot call setState on an unmounted component. Previously I handled this error with this.isMounted. Now I was trying to handle it using promise cancelling in componentWillUnmount as mentioned in the React Blog.
this.cancellablePromise = makeCancelable(getSearchResults(word));
this.cancellablePromise.promise
.then(res => {
console.log({ res });
this.setState({ values: res });
})
.catch(err => console.log("error", err));
console.log("in data ", this.cancellablePromise);
}
The cancellablePromise gets assigned after the promise got resolved. So there is a null object in componentWillUnMount for cancellablePromise instance.
Looks like you just need to do the following thing:
myAwesomeMethod = () => {
this.cancellablePromise = makeCancelable(getSearchResults(word));
this.cancellablePromise
.then(...)
.catch(...)
}
componentWillUnmount() {
this.cancellablePromise && this.cancellablePromise.cancel();
}
this.cancellablePromise will be undefined only in the case when you unmount your component before the call of the method with promise call.
The issue is that your handleChange method calls debouncedGetSearchResult, but you are initializing this.cancellablePromise in getSearchResult. This leaves a 500ms window for the unmount to happen before you have initialized this.cancellablePromise.
You need to rework this so that the debouncing is part of the cancelable promise rather than prior to it.
I've got a simple component that renders a table. The rows are mapped like this:
render () {
return (
{this.state.data.map(function(row, i){
return <Row row={row} key={i}/>
}.bind(this))}
)
}
The state is initialized in the constructor:
this.state = {
data: props.hasOwnProperty('data') ? props.data : [],
route: props.hasOwnProperty('route') ? props.route : null
}
The data can be initialized in the DOM, or after, the route is passed to the container and bound correctly. In this case, I 'm doing it after in the componentDidMount method:
componentDidMount () {
axios.get(this.state.route)
.then(function(resp){
this.setStateParametersFromAjax(resp);
}.bind(this))
.catch(function(err){
console.log(err);
})
}
The setStateParametersFromAjax(resp) method is defined here:
this.setState({
data: resp.data.data,
});
This all works flawlessly on DOM load. However, there are buttons that will perform subsequent requests later on. These requests perform the same axios call.
The problem is, that even though the state is updated (verified by adding a callback as the 2nd argument to the setState method and logging this.state), the DOM does not update.
What do I need to do to make it so that the DOM updates with this new data as well?
Edit
I had simplified the code a bit, there is a method called fetch() that accepts an argument of params that defines the ajax call:
fetch (params) {
if(typeof params != "object") {
params = {};
}
axios.get(this.state.route, {
params
}).then(function(resp) {
this.setStateParametersFromAjax(resp);
}.bind(this))
.catch(function(err){
console.log(err);
})
}
The componentDidMount() method calls this on load:
componentDidmMount () {
this.fetch();
}
When a button is clicked later, this calls a function that calls the fetch method with parameters:
<li className="page-item" onClick={this.getNextPage.bind(this)}>
Where the function is defined:
getNextPage (event) {
event.preventDefault();
this.fetch({
arg: val
});
}
You should use a unique key value other than index. Even the state is updated, react may not update DOM if the key not changed.
https://facebook.github.io/react/docs/reconciliation.html