inconsistent execution of functions in react - javascript

i'm trying to get data from the server and write it to a state, but the functions are not firing sequentially
I have a file core.js with with fuctions set
export var LoginAPI = {
signIn: (signInData) => {
request.useQuery(signInData, 'Autorize', 'LogIn').then(Request => {
if (Request.flag) {
return true;
}
else {
GeneralAPI.showNotificationError("Ошибка входа", Request.answer)
return false;
}
})
}
}
request is simple fetch to sigin method into .net core identity
and i have a some page where i need to use it
`class NormalLoginForm extends Component {
//somecode
onFinish = (e) => {
var LoginDatas = {
Login: this.formRef.current.getFieldValue("loginFormItem"),
Password: this.formRef.current.getFieldValue("passWordFormItem")
}
var signIn = core.LoginAPI.signIn(LoginDatas)
this.props.store.isAuthorizeChange(signIn)
console.log("result")
}
render() {
return (
<Form >
<somefFormComponents>
</Form>
);
}
}`
And i have a problem
this function is executed first is this.props.store.isAuthorizeChange(signIn) and only the second one makes a request to the server.
how can this be fixed?
I tried to wrap
var signIn = core.LoginAPI.signIn(LoginDatas)
into Promise but all the same, first changes were called in the storage and only then the resolve method in the promise

Related

i want to code this react function to get data from thirdweb and display

Help me to get fetch information from blockchain and display in the browser. i want know how to call this thirdweb functions in react.
Below code is a solidity code used to create a user in our system.
function createUser(string memory _userId, string memory _fName, string memory _lName, string memory _mobile, string memory _dob, uint256 _age, string memory _nationality, string memory _gender) public {
if(!chkexisitinguserId(_userId)){
users[_userId] = User(_fName, _lName, _mobile, _dob, _age,_nationality,_gender);
noofUser++;
allUserId[k] = _userId;
k++;
}
}
function getUser(string memory _userId) public view returns (string memory, string memory, string memory, string memory, uint256, string memory, string memory) {
User memory user = users[_userId];
return (user.fName, user.lName, user.mobile, user.dob, user.age, user.nationality, user.gender);
}
The below code is thirdweb libary code to interact with smart contract. The below code is stored in refer.js file.
import { useContract, useContractWrite } from "#thirdweb-dev/react";
export default function Component() {
const { contract } = useContract("0xBB417720eBc8b76AdeAe2FF4670bbc650C3E791f");
const { mutateAsync: createUser, isLoading } = useContractWrite(contract, "createUser")
const call = async () => {
try {
const data = await createUser([ "John0312", "John", "s", "8090890367", "03-11-2000", 20, "India", "M" ]);
console.info("contract call successs", data);
} catch (err) {
console.error("contract call failure", err);
}
}
}
export default function Component() {
const { contract } = useContract("0xBB417720eBc8b76AdeAe2FF4670bbc650C3E791f");
const { data, isLoading } = useContractRead(contract, "getUser", _userId)
}
The smart contract is deployed in thirdweb and trying to access it. I am stuck at how to call this "call" async function from app.js.
import React, { useEffect } from 'react'
function App(){
const handleclick = async (e) => {
await call();
}
return (
<button onClick={handleclick}>click me</button>
)
}
export default App
it generates error like undefined function call().
I would create a new hook (useCall.js) who's job is simply to instantiate the useContract and useContractWrite hooks, then define the call() method for you to use in any component.
In this example, call() is the only thing returned from the hook. It's wrapped inside useCallback to ensure it's only defined when createUser is defined.
export default function useCall() {
const { contract } = useContract("0xBB417720eBc8b76AdeAe2FF4670bbc650C3E791f");
const { mutateAsync: createUser, isLoading } = useContractWrite(contract, "createUser")
const call = React.useCallback(async () => {
try {
const data = await createUser([ "John0312", "John", "s", "8090890367", "03-11-2000", 20, "India", "M" ]);
console.info("contract call successs", data);
} catch (err) {
console.error("contract call failure", err);
}
}, [createUser]);
return call;
}
Now inside of any component you can use the hook and get the call() function:
import useCall from './useCall';
export default function Component() {
const call = useCall();
useEffect(() => {
(async () => {
await call();
})();
}, []);
}

How to access a component function from main.js in Vue 3 with Composition API

Using Vue 3 and composition API I have a component that have this function:
const retrieveSignedJWT = async (callback) => {
if (jwtUrl.value && !callback) {
//console.log("There's no callback use the by default URL")
await fetch(jwtUrl.value)
.then(async (response) => {
const data = await response.text();
// check for error response
if (!response.ok) {
// get error message from body or default to response statusText
const error = (data && data.message) || response.statusText;
return Promise.reject(error);
}
let jwt = data;
token.value = data;
decodeToken(jwt);
retrieveCategories();
})
.catch((error) => {
errorMessage.value = error;
console.error("There was an error!", error);
});
} else {
//Function has a callback
token.value = callback;
}
};
What I need to do is to find a way to expose the previous component function so I can call it from the main.js. The scenario is that I'm creating an IIFFE with Vue 3 and Vite (a widget that the end user will load from a script) and hooking up a public function to it so the user can use it at any point in their code. That function can have or not have a callback that will expose a token implemented.
import { createApp } from "vue";
import "#/assets/styles/index.scss";
import App from "./App.vue";
import store from "./store";
let div = document.createElement("div");
document.body.appendChild(div);
div.setAttribute("id", "my-widget");
window.myWidget = {
load: function (endUserRetrievedJWT) {
if (endUserRetrievedJWT) {
const endUserJWT = endUserRetrievedJWT();
//Calling my component function w a call back
retrieveSignedJWT(endUserJWT);
} else {
//Calling my component function without a call back
retrieveSignedJWT();
}
},
};
createApp(App).use(store).mount("#my-widget");
So basically I'm trying to find a way to invoke the parent component function from the main.js file in order to manage how to save a token to the state of my application. That token can come from a default URL or in the shape of a callback function that the end-user will pass as an argument to the globally expose function coming from main.js.
main.js is meant for setting up your Vue application. Don't use this for any other code! It won't work.
Simply create a separate .js file (e.g. utils.js) and export the function from there.
I'm not completely sure what you're trying to achieve exactly but it looks like an authentication process for logging in. What you're probably trying to do is call the login/logout functions from within a Vue component? This could be as simple as
// Separate file, e.g. `authentication.js`
export const login = (cb) => {
// do not name the callback function (cb) 'callback' as that may get you unexpected behavior
// Your code
somePromise().then((res) => {
cb(res);
});
}
// Your component
import { login } from 'path/to/authentication';
login(myCallback);
const myCallback = (res) => {
...
};
I finally ended up exposing the function in the mounted hook like this:
onMounted(() => {
window.myWidget = {
load: retrieveEndUserJWT,
};
retrieveDataAttributes();
callWebsocket(websocket.value);
});
Then inside the same component, I create a method that will process the callback:
const retrieveEndUserJWT = async (endUserRetrievingTokenCallback) => {
const jwt = await endUserRetrievingTokenCallback();
processingToken(jwt);
};
And in the processingToken method, I deal with that token coming from the end-user callback function. I still have to navigate the pros and cons of exposing the function in the mounted hook.

Nuxt Composition API, updating 'state', not reflected on UI Template

I had a Nuxt.js application working with the options API. And with the new Nuxt3 coming out, I was trying to migrate things over to the supposedly 'better' alternative. So far i've had nothing but challenges, perhaps that's my lack of knowledge.
I'm building a basic E-Commerce platform with a component of
# products/_id.vue
<template>
<div>
{{ product }}
</div>
</template>
<script>
import {
defineComponent,
useFetch,
useStore,
useRoute,
ssrRef, reactive, watch
} from '#nuxtjs/composition-api'
export default defineComponent({
setup () {
const store = useStore()
const route = useRoute()
const loading = ref(false)
// LOAD PRODUCT FROM VUEX STORE IF ALREADY LOADED
const product = reactive(store.getters['products/loaded'](route.value.params.id))
// GET PAGE CONTENT
const { fetch } = useFetch(async () => {
loading.value = true
await store.dispatch('products/getOne', route.value.params.id)
loading.value = false
})
// WATCH, if a use navigates to another product, we need to watch for changes to reload
watch(route, () => {
if (route.value.params.id) {
fetch()
}
})
return {
loading
product
}
}
})
</script>
One thing I need to note, is, if the product gets a comment/rating, I want the UI to update with the products star rating, thus needing more reactivity.
I continue to get an undefined product var
Inside my VueX store I have my getters
loaded: state => (id) => {
try {
if (id) {
return state.loaded[id]
}
return state.loaded
} catch {
return {}
}
}
Looking for directions on how to get this to work, improve any of the code i've currently setup.
If you want to maintain reactive referece to your getter, then you have to create a computed property.
So, what you return from your setup function is
product: computed(() => getters['products/loaded'](route.value.params.id))
This will make sure that whenever the getter updates, your component will receive that update.
Also, if the product already exists, you should bail out of the fetch function. So that you do not make the extra API call.
And, finally, if there is an error, you could redirect to a 404 error page.
All in all, your setup function could look something like this
setup() {
const route = useRoute();
const { error } = useContext();
const { getters, dispatch } = useStore();
const loading = ref(false);
const alreadyExistingProduct = getters['products/loaded'](route.value.params.id);
const { fetch } = useFetch(async () => {
// NEW: bail if we already have the product
if (alreadyExistingProduct) return;
try {
loading.value = true;
await dispatch('products/getOne', route.value.params.id);
} catch {
// NEW: redirect to error page if product could not be loaded
error({ statusCode: 404 });
} finally {
loading.value = false;
}
});
watch(route, () => {
if (route.value.params.id) {
fetch();
}
});
return {
loading,
// NEW: computed property to maintain reactive reference to getter
product: computed(() => getters['products/loaded'](route.value.params.id)),
};
},
You will probably also run into this harmless issue FYI.

not able to access class methods using the class instance returned by a static method

I have created a subscriber class to store subscriber details and use a static method to return the instance of the class, but I am not able to set the values using the instance
Here is the subscriber class:
let _instance;
export class Subscriber {
constructor(username, password) {
this._username = username;
this._password = password;
}
setSubscriberId(subscriberId) {
cy.log(subscriberId);
this._subscriberId = subscriberId;
}
setSessionId(sessionId) {
this.sessionId = sessionId;
}
getUserName = () => {
return this._username;
}
getPassword = () => {
return this._password;
}
getSubsciberId() {
return this._subscriberId;
}
getSessionId() {
return this.sessionId;
}
static createSubscriber(username, password) {
if (!_instance) {
_instance = new Subscriber(username, password);
}
return _intance;
}
static getSubscriber() {
return _instance;
}
}
I am creating a instance of the class in before block and accessing the instance in Given block
before("Create a new subscriber before the tests and set local storage", () => {
const username = `TestAutomation${Math.floor(Math.random() * 1000)}#sharklasers.com`;
const password = "test1234";
subscriberHelpers.createSubscriber(username, password, true).then((response) => {
cy.log(response);
Subscriber.createSubscriber(username, password);
Subscriber.getSubscriber().setSubscriberId(response.Subscriber.Id);
Subscriber.getSubscriber().setSessionId(response.SessionId);
}).catch((error) => {
cy.log(error);
});
});
Given(/^I launch selfcare app$/, () => {
cy.launchApp();
});
Given(/^I Set the environemnt for the test$/, () => {
cy.log(Subscriber.getSubscriber());
cy.log(Subscriber.getSubscriber().getSubsciberId());
});
here is the output on the cypress console
Questions:
Why the subscriberID is null even though I am setting it in the before block
if I print the subscriber Object why am I not seeing subscriberID
Here is the output of subscriber object
Properties username and password are defined synchronously in before(), so are present on the object when tested.
But subscriberId is obtained asynchronously, so you will need to wait for completion inside the test, e.g
cy.wrap(Subscriber.getSubscriber()).should(function(subscriber){
expect(subscriber.getSubsciberId()).not.to.be.null
})
Refer to wrap - Objects to see how to handle an object with Cypress commands.
and see should - Differences
When using a callback function with .should() or .and(), on the other hand, there is special logic to rerun the callback function until no assertions throw within it.
In other words, should will retry (up to 5 seconds) until the expect inside the callback does not fail (i.e in your case the async call has completed).

flickering doing setState using nested api calls in react

I want to load a bunch of data that involves multiple APIs, I did setState in foreach, it worked but I think the design is wrong, as I see flickering on my screen.
API.fetchMain().then(main => {
main.forEach(o => {
const main_id = o.main_id
this.setState({
main: o
})
API.fetchSub(main_id)
.then(sub => {
this.setState({
sub
})
API.fetchOthers(main_id, sub.id)
.then(others => {
this.setState({
others
})
})
})
})
}
I think I should use promises to refactor, I tried but I think my design was wrong.
API.fetchMain().then(main => {
let promise = []
main.forEach(o => {
const main_id = o.main_id
this.setState({
main: o
})
promise.push(
API.fetchSub(main_id)
.then(sub => {
return API.fetchOthers(main_id, sub.id)
})
)
})
Promise.all(promise).then(resp => console.log('do setState here'))
}
Need help.
It looks to me that you are fetching a resource that provides you with information about how to make further requests. If you are open to using a fetch library I would recommend axios. Heres how I would envision it looking
import axios from 'axios'
fetch(){
// Make the initial request
var options = { url: "URL of main resource", method: "GET" }
axios(options).then(res => {
// Create an array of next requests from the response
var next_requests = res.data.main.map(id => axios.get(`${resource_url}/${id}`))
//Make the requests in parallel
axios.all(next_requests).then(axios.spread(() => {
//since we don't know how many request we can iterate
//over the arguments object and build the new state
var newState = {}
arguments.forEach(i => {
// how you want to structure the the state before setting it
})
this.setState(newState)
})
}).catch(err => //error handling logic here)
}
From my understanding of your question you could also (since you are using react) break your fetch request into components that get called when they mount. A quick example:
const class MainComp extends Component {
constructor(props){
super(props)
this.state = {
main: []
}
}
componentDidMount(){ this.fetchMain() }
fetchMain() {
axios.get('url').then(res =>
this.setState({main_id: res.data.main.id})
}
sendSubFetchToParent(dataFromChild){
// Do what you need to with the data from the SubComp child
}
render(){
return (
{this.state.main.map(id => <SubComp id={id) afterFetch={this.sendSubFetchToParent}/>}
)
}
}
const class SubComp extends Component {
componentDidMount(){ this.fetchSub() }
fetchSub() {
//Pass the results to the parent after the fetch completes.
// You can add the usual error handling here as well.
axios.get('url').then(res => this.props.afterFetch(res.data))
}
render(){
//Return null or render another sub component for further nested requests
return null
}
}
In the above, MainComp initiates a request. When it gets a response (which in your example is an array) we set that response to the state. This triggers rerender which will mount n number of SubComp. When those mount they will initiate their requests to get data. For SubComp we pass a callback from the parent so SubComp can send its fetch response back to MainComp (And handle it appropriately by setting state etc etc). You can return null in SubComp or have it mount a component that will make further request.
In that way your fetch requests are now componentized.

Categories

Resources