Web3 batch request return undefined - web3js

I'm trying to call approve function for BNT and another ERC20 via BatchRequest.
First request works good, but second return undefined, the same if I swap order.
Also if I cancel first transaction, second works good.
wrapperApprove = async () => {
// GET DATA
const web3 = this.props.MobXStorage.web3
let batch = new web3.BatchRequest()
const amount = await this.calculateConnectorBySmartTokenAmount()
const tokenInfo = this.getInfoBySymbol()
const converterAddress = tokenInfo[1]
const connectorAddress = tokenInfo[2]
const bnt = this.props.MobXStorage.web3.eth.Contract(ABISmartToken,
BNTToken)
const connector =
this.props.MobXStorage.web3.eth.Contract(ABISmartToken,
connectorAddress)
// MAKE BATCH REQUEST
batch.add(connector.methods.approve(
converterAddress,
this.props.MobXStorage.web3.utils.toWei(String(amount[1]))
).send.request({from: this.props.MobXStorage.accounts[0]}))
batch.add(bnt.methods.approve(
converterAddress,
this.props.MobXStorage.web3.utils.toWei(String(amount[0]))
).send.request({from: this.props.MobXStorage.accounts[0]}))
batch.execute()
}

Related

Return value from Google Places getDetails callback asynchronously

Is it possible to make a Google Places callback from getDetails function asynchronus or return it's value?
Essentially, in my react app, I am trying to do the following:
pass a placeId to google places api
wait for google to bring back some place information (address, photos, etc)
make a call to my local api to do something with this data from google
What happens though is
google goes to get the data
the call to my api is made but google has not brought back the data yet
I have tried using useState however, the state is not updated right away and thus I am not sure how to "wait" for google places to finish getting data before continuing my call
example of what I am trying to do (obviously wrong)
const [value, setValue] = useState('')
const foo = async (placeId) => {
var service = new window.google.maps.places.PlacesService(
predictionsRef.current,
)
await service.getDetails(
{
placeId,
fields: ['photos'],
},
async place =>
await setValue(
place.photos[0].getUrl({ maxWidth: 1280, maxHeight: 720 }),
),
)
// I want 'value' to have google place data before the axios call
await axios.post(...)
}
I have looked at the following links so far but can't piece together what I need:
google places library without map
https://gabrieleromanato.name/javascript-how-to-use-the-google-maps-api-with-promises-and-async-await
useState set method not reflecting change immediately
You could make it this way,
const [value, setValue] = useState('')
const [placeID, setPlaceID] = useState(null)
a function to return a promise from google placeDetails API,
const getPlaceDetails = (ref) => {
return new Promise(function (resolve, reject) {
let placesService = new window.google.maps.places.PlacesService(ref);
placesService.getDetails(
{
placeId,
fields: ['photos'],
},
(place) => {
resolve(place.something);
}
);
});
};
an effect that triggers upon placeID change
useEffect(() => {
async function doStuff() {
let placesResponse = await getPlaceDetails(ref);
let myResponse = await yourAPICall(placesResponse);
setValue(placesResponse);
}
if(placeID !==null){
doStuff();
}
}, [placeID]);
I haven't tested this code, but hope this approach helps.

In react, object is seems to be as an empty object for using fetch

If I use a variable instead of using react state object inside a function is behaving weirdly for fetch. If i remove the const response..... and const data.... line things works just fine but If i use fetch function and use normal variable without using state this doesn't work. Why is that?
Object is showing normal if i log it from inside the function
Object is also showing normal if i use const variable
Object is showing like an empty object if i log it from outside the function
But this code works just fine..
const [services, setServices] = useState([]);
useEffect(() => {
const API_URL = "http://localhost:8080/getServiceName/3";
const loadData = async () => {
const apiData = [];
const response = await fetch(API_URL);
const data = await response.json();
data.services.map(service => (
apiData.push(service.service_name)
));
setServices(apiData);
}
loadData();
}, [location])
And notice that i can add more value to a const variable(const dummyLocation{in image} and const apiData in code)!, How??
loadData(); is asynchronous, so if you do
loadData()
console.log(dummyLocation)
then the console.log will happen before loadData completed. You probably just want to do
loadData().then(() => console.log(dummyLocation))
As for the questions regarding why you can do:
const apiData = [];
// ...
apiData.push(service.service_name)
the reason is that const doesn't mean the variable can't change (per se), but instead that the variable will never be reassigned - you can't do:
const apiData = [];
apiData = [service.service_name];
because that is assigning a new array to it.

How to update react useState without delay?

When I call fetchProducts I want productPage state to be updated before it runs the next line of code since the next line requires the updated state.
The state only gets updated after the function has finished running. No matter where in the fetchProducts function I put console.log(productPage) it returns the state as it was before the function was called.
const [productPage, setProductPage] = useState(1)
const [displayProducts, setDisplayProducts] = useState([])
const fetchProducts = async () => {
setProductPage(productPage + 1) // DOES NOT UPDATE UNTIL AFTER FUNCTION RUNS
const newProductsData = await fetch(`/api/getproducts?page=${productPage}`)
const newProductsArr = await newProductsData.json()
setDisplayProducts(displayProducts.concat(newProductsArr))
}
Is this possible? I've found workarounds to the problem but it feels hacky and not ideal.
I'm using next.js also, I'm not sure if that would make a difference. I can't use normal variables as they reset on each render.
setProductPage will update the state and trigger a new render. productPage is not the state, it's just a variable holding the value of the state the moment you used useState. It will never change, it will always have the same value. You think it changes, but in reality, the function is simply executed again, but now productPage assigned with the new value.
So what can you do? You have two options.
The one it use useEffect, that will see if productPage changes (every time the function is executed = re-renders), and if it is, it will fetch the data and use setDisplayProducts to re-render the component with a new value in displayProducts. This is nice if you plan to have other ways of updating the productPage and you want them to also trigger the fetch.
const [productPage, setProductPage] = useState(1)
const [displayProducts, setDisplayProducts] = useState([])
const fetchProducts = async () => {
setProductPage(productPage + 1);
}
useEffect(() => {
const getDisplayProducts = async () => {
const newProductsData = await fetch(`/api/getproducts?page=${productPage}`)
const newProductsArr = await newProductsData.json()
setDisplayProducts(displayProducts.concat(newProductsArr))
};
getDisplayProducts();
}, [productPage]);
The second one is just store the new value in a variable, pass the variable to the setProductPage but use the variable in the fetch and not productPage.
const [productPage, setProductPage] = useState(1)
const [displayProducts, setDisplayProducts] = useState([])
const fetchProducts = async () => {
const nextProductPage = productPage + 1;
setProductPage(nextProductPage);
const newProductsData = await fetch(`/api/getproducts?page=${nextProductPage}`)
const newProductsArr = await newProductsData.json()
setDisplayProducts(displayProducts.concat(newProductsArr));
};
Setting a state is an async operation and you can't use it like a sync operation.
So, you must use useEffect hook, which runs after state changes.
import React, {useState, useEffect} from 'react';
const [productPage, setProductPage] = useState(1)
const [displayProducts, setDisplayProducts] = useState([])
const fetchProducts = async () => {
setProductPage(productPage + 1)
}
useEffect(() => {
const newProductsData = await fetch(`/api/getproducts?page=${productPage}`)
const newProductsArr = await newProductsData.json()
setDisplayProducts(displayProducts.concat(newProductsArr))
}, [productPage]); // <-- monitor productPage for changes

React - set localstorage with axios data before continuing

am having a small challenge setting up a proper initialization for my react app.
Having some settings in localstorage, I'd want to populate them with the data coming from an axios get request, before ANYTHING else in the app happens (e.g. initialization of the rest of the constructor lines).
What happens currently is that whilst the line executes, the code continues and reads the 'old' localstorage, which is not yet updated:
APP.JS
...
this.readSettingsDB(false);
this.state = {
chartTimeAggregationType: JSON.parse(localStorage.getItem('timeAggregationType')) // <-- This value is still old
dataLoading: true,
...
readSettingsDB(refreshPage) {
data = axios.get('/someurl').then(response => {
localStorage.setItem('timeAggregationType': reponse.time)
});
}
Where are you using refreshPage? Here is how I would handle your issue.
readSettingsDB = async (refreshPage) => { // arrow function make async
const data = await fetch('/someurl'); // use fetch
const response = await data.json();
localStorage.setItem('timeAggregationType': reponse) // set storage
});
}
If you want to setState first, setState comes with a callback.
readSettingsDB = async (refreshPage) => { // arrow function make async
const data = await fetch('/someurl'); // use fetch
const response = await data.json();
this.setState({
timeAggregationType: reponse
}, () => {
localStorage.setItem('timeAggregationType': this.state.timeAggregationType) // set storage
});
})
}

Firebase On Value get state react hooks

i'm using firebase and react hooks, my problem is that I need to check if the driverId that i have is still in the drivers list, but the problem is that inside the event, inputs.driverId is null, even if it already have a value, and if a "print" the inputs variable all the flelds are like when i declared the initial state.
const initialState = {
driverId:'',
drivers: []
};
const [inputs, setInputs] = useState(initialState);
const getDrivers = () => {
const self = this;
const nameRef = firebase.database().ref().child('drivers').orderByChild('status');
nameRef.on('value', snapshot => {
var drivers = snapshot.val();
setInputs(inputs => ({...inputs, ['drivers']: drivers}));
console.log('dtiverId', inputs.driverId) // console response: dtiverId
})
}
anyvody that can help me, i need when the event excutes check if the select driver (driverId) is still in the list, but when i check driverId i get null, only inside the event
firebase.database() is an asynchronous call. You need to add async and await like so
const getDrivers = aysnc () => {
const self = this;
const nameRef = await firebase.database().ref().child('drivers').orderByChild('status');
nameRef.on('value', snapshot => {
var drivers = snapshot.val();
setInputs(inputs => ({...inputs, ['drivers']: drivers}));
console.log('dtiverId', inputs.driverId) // console response: dtiverId
})
}
What is happening in your code is that you are trying to use driverId before it is returned from firebase (which is why it is null). Async will block until firebase returns then your code will resume executing.
The firebase realtime database works asynchronously.
You should make use of async await or promises to get the data.
The examples in the
firebase docs show how to get the data using promises.

Resources