I cant get userData value out of axios function. Console says that userData is undefined but thats not the case. I guess it has something with async/await but I am not sure how to use it.
var userData;
async function getData() {
const data = {
KorisnickoIme: 'uros'
};
const url ='https://localhost:44357/api/Fin/ProfileSetUp';
axios.post(url, data).then((result)=>{
window.userData = result.data.split(";");
}, []).catch((error)=>{
alert(error);
})
}
getData();
console.log(window.userData);
const [email, setEmail] = useState(window.userData[1]);
I am tried to treat userData as global variable but without any luck.
You're doing it backwards. Don't try to stop the component from rendering at all while you load asynchronous data. (That is... Don't try to use the result of the asynchronous operation to define the initial state.) Define the initial state of the component, then load the data to update that state.
For example, the initial state can be undefined:
const [email, setEmail] = useState();
or perhaps an empty string:
const [email, setEmail] = useState('');
or whatever value you like. Then define the operation which fetches data and updates state:
function getData() {
const data = {
KorisnickoIme: 'uros'
};
const url ='https://localhost:44357/api/Fin/ProfileSetUp';
axios.post(url, data).then((result)=>{
setEmail(result.data.split(";")); // Use the setter to update React state
}, []).catch((error)=>{
alert(error);
});
}
Then use useEffect to invoke that operation when the component first loads:
useEffect(() => {
getData();
}, []);
So the component will first render with the initial default state, then after the asynchronous operation completes it will re-render with the new updated state.
Note the empty dependency array passed to useEffect here. That would cause the operation to run once, when the component initially loads. Adding any values to the dependency array would cause the operation to run any time the component re-renders with changes to those values. Omitting the array entirely would cause the operation to run on every render (which you probably don't want in this case).
Related
I have an array of results coming from an API that I called using axios. get(). Then the result is in array and I want to map it into table in react js.
Below is the API fetching data
const [data, getData] = useState([])
useEffect(() => {
axios.get("http://localhost:4000/api/authentication/history")
.then(result =>{
console.log(result.data.result)
getData(JSON.stringify(result.data.result))
console.log(data.length)
})
}, [])
The line console.log(data.length) returns 0. I dont know why the data is not stored in the data function. That is why when I map {data.map} into it will return error as data.map is not a function. So, is there a simpler way to display and map this array of result into react js table?
Here is the image of the array of result (it is not in json type but in array)
Update #1
Since posting this (7 hours ago), I tried to do this myself, and realised I completely invented this feature, and callback isn't actually a function of useState
I did some research and came across this very useful function:
const useStateCallback = (initialState) => {
const [state, setState] = useState(initialState);
const cbRef = useRef(null); // init mutable ref container for callbacks
const setStateCallback = useCallback((s, cb) => {
cbRef.current = cb; // store current, passed callback in ref
setState(s);
}, []); // keep object reference stable, exactly like `useState`
useEffect(() => {
// cb.current is `null` on initial render,
// so we only invoke callback on state *updates*
if (cbRef.current) {
cbRef.current(state);
cbRef.current = null; // reset callback after execution
}
}, [state]);
return [state, setStateCallback];
};
Original
I don't know what getData is, but I'll assume it's state, and you have something like this:
const [data, getData] = useStateCallback(); // previously useState
If that's the case, when you call your getData, you can do a callback as the 2nd argument. That callback happens when your state updates successfully:
...
getData(JSON.stringify(result.data.result), () => console.log(data.length));
...
If that's now how you're doing it, then I'd suggest you change whatever you're doing to be in state, and also rename getData to setData
Explanation
When you're calling your getData, you're telling react that you want to update your data? Great! The thing to note is, react doesn't do this update immediately. Instead, it updates it (and other state) in the future, all at the same time.
With that in mind, you pass the callback function as the 2nd argument to tell react what you want to happen once this specific state has been updated
As for getData to setData? That's because the function doesn't return (get) anything, but does set something. Makes your code clearer
I am trying to determine if a customer has an active subscription or not. To do this I am utilizing the following code:
const stripe = require('stripe')('some-api-key');
export default function Example(){
// the user will automatically be considered non-subbed by default
const [isSubscriber, setIsSubscriber] = useState(false)
// grab the customer id from stripe
async function get_customer_id() {
const customers = await stripe.customers.search({
query: `metadata[\'some-meta-data-key\']:\'some-meta-data-value\'`
});
return customers.data[0]['id']
}
// grab the list of active subscriptions from stripe
async function customer_is_subscriber(){
const subs = await stripe.subscriptions.list({
status: 'active',
});
return subs
}
// determine if the customer id is in the list of active subscriptions.
// return true if so, false otherwise
async function test_equality(){
const customer_id = await get_customer_id();
const subbed = await customer_is_subscriber();
const answer = subbed.find(sub => sub.customer === customer_id)
return !!answer;
}
useEffect( () => {
async function load_result() {
const promise_function_return = await test_equality()
setIsSubscriber(promise_function_return)
}
load_result();
}, [isSubscriber]);
return (
// some react code
)
}
I have been able to successfully get all of my other functions where I am doing the comparisons for if a user is a subscriber but where I am having an issue is updating the state value (e.g. true if they are subbed, false otherwise).
I found some good past questions on this specific topic such as:
here The useState set method is not reflecting a change immediately
here: setState inside Promise in React
and here: setState inside a Promise function in a useEffect with hooks?
but I just have not been able to get it working correctly. This is currently the closest I have been able to get to solving this problem.
Currently your code says that, when isSubscriber changes, it should check if the user is a subscriber and update the isSubscriber state... so it's a chicken and egg problem. It won't set isSubscriber until isSubscriber gets set.
I think you want to change }, [isSubscriber]); to }, []); so that that code executes when the component first loads (not when isSubscriber changes).
The useEffect hook will always run on mount regardless of if there is anything in its dependency array. This means that your useEffect will work as is, and will run onMount as well as when isSubscriber changes:
useEffect( () => {
async function load_result() {
const promise_function_return = await test_equality()
setIsSubscriber(promise_function_return)
}
load_result();
}, [isSubscriber]);
To verify this, you can check out this codesandbox example. The useEffect looks just like yours, and you will notice that isSubscriber is initially set to false, but is updated to true after 3 seconds.
There's still an adjustment you may want to make even though that part appears to work ok. With isSubscriber in the dependency array, the function in your useEffect will be called any time isSubscriber changes. This probably not what you want, since this function doesn't actually depend on isSubscriber, but actually sets isSubscriber. In this case, that means test_equality() will be run on initial mount and then one more time after it sets isSubscriber, which is unnecessary.
This blog post explains the useEffect dependency array really well.
You can fix this by removing isSubscriber from the dependency array, like this:
useEffect(() => {
console.log("in useEffect");
async function load_result() {
const promise_function_return = await test_equality();
setIsSubscriber(promise_function_return);
}
load_result();
}, [isSubscriber]);
Since you mentioned the state value is not getting updated, there must be another issue going on in either get_customer_id() or customer_is_subscriber(). It would be good to double check and make sure the stripe api calls are working as expected.
I am new to React and I have some doubt regarding useState hook.I was recently working on an API based recipe react app .The problem I am facing is when I submit something in search form a state change should happen but the state is not changing but if I resubmit the form the state changes.
import React,{useState,useEffect} from "react";
import Form from "./componnents/form";
import RecipeBlock from "./componnents/recipeblock"
import './App.css';
function App() {
const API_id=process.env.REACT_APP_MY_API_ID;
const API_key=process.env.REACT_APP_MY_API_KEY;
const [query,setQuery]=useState("chicken");
const path=`https://api.edamam.com/search?q=${query}&app_id=${API_id}&app_key=${API_key}`
const [recipe,setRecipe]=useState([]);
useEffect(() => {
console.log("use effect is running")
getRecipe(query);
}, []);
function search(queryString){
setQuery(queryString);
getRecipe();
}
async function getRecipe(){
const response=await fetch(path);
const data=await response.json();
setRecipe(data.hits);
console.log(data.hits);
}
queryString in search() function holds the value of form input,Every time I submit the form this value is coming correctly but setQuery(queryString) is not changing the query value or state and if I resubmit the form then it change the state.
The code you provided something doesn't make sense.
useEffect(() => {
console.log("use effect is running")
getRecipe(query);
}, []);
Your getRecipe doesn't take a variable. But from what I am understanding whenever you search you want to set the Query then get the recipe from that Query.
With the useEffect you can pass in a parameters to check if they changed before running a function. So update the setQuery then when the component reloads it will fire the useEffect if query has changed. Here is the code to explain:
useEffect(() => {
console.log("use effect is running")
getRecipe(query); <-- this doesn't make sense on your code
}, [query]);
function search(queryString){
setQuery(queryString);
}
By doing this when the state updates it causes the component to re-render and therefore if query has changed it will call your getRecipe function.
The main issue in your code is that you are running getRecipe() directly after setQuery(queryString). setQuery(queryString) is asynchronous and will queue a state change. When you then run getRecipe() directly after, the state will still hold the old value of query (and path) and therefore does not fetch the new data correctly.
One solution would be to call getRecipe() within a useEffect() dependent on path.
useEffect(() => {
getRecipe();
}, [path]);
function search(queryString){
setQuery(queryString);
// getRecipe() <- removed
}
With [path] given as dependencies for useEffect(), getRecipe() will be called automatically whenever path changes. So we don't have to call it manually from search() and therefore can remove getRecipe() from the function body. This also makes the current useEffect() (without [path] dependency) redundant, so it can be removed.
Another solution would be to provide the new query value through the getRecipe() parameters, removing the dependency upon the state.
function search(queryString){
setQuery(queryString);
getRecipe(queryString);
}
async function getRecipe(query) {
const path = `https://api.edamam.com/search?q=${query}&app_id=${API_id}&app_key=${API_key}`;
const response = await fetch(path); // <- is no longer dependent upon the state
const data = await response.json();
setRecipe(data.hits);
}
This does require moving the path definition inside getRecipe().
I have a function inside of my functional component that uses a value saved in state. However, when it is called, it has the original value in state, not the updated value. When I look at my component in Chrome React Dev Tools, I see that the updated value is stored in state. Aren't functions supposed to get the latest state value in React? I didn't think I'd have to wrap my functions in a useEffect every time some value in state they depend on changes. Why is this happening?
const Editor = (props) => {
const [template, setTemplate] = useState(null);
const [openDialog, setOpenDialog] = useState(false);
useEffect(() => {
if (props.templateId) {
getTemplate(props.templateId));
}
},[]);
const getTemplate = (templateId) => {
{...make API to get template...}
.then((response) => {
if (response.template) setTemplate(response.template);
});
}
/* THIS FUNCTION SAYS TEMPLATE IS ALWAYS NULL */
const sendClick = async () => {
if (template) {
await updateTemplate();
} else {
await initializeTemplate();
}
setOpenDialog(true);
};
}
UPDATE: I figured out the issue. The sendClick function is being used inside an object that I have in state. When that object is created, it creates a version of the sendClick function based on the state at that time. I realized I needed to refactor my code so that the function is not stored within my object in state so that the function will always have the latest state values.
Please correct the code there its setTemplate(template)); not getTemplate(template));
I'm guessing that you have that right in the source code... if Yes then,
You have got into a trap that all developers new to React fall into.
This code is betraying you ...
useEffect(() => {
if (props.template) {
setTemplate(template)); // Mentioned as getTemplate(template));
}
},[]); // Here is where you make the mistake
The second argument you pass to the useEffect is called as Dependencies. Meaning if your useEffect is dependent on any state or any variable or function, Ii should be pass as the second argument inside the []. By now you should have got the answer.
Clearly, your useEffect is dependent on template. You should pass that inside the [].
So the code will be : -
useEffect(() => {
if (props.template) {
setTemplate(template)); // Mentioned as getTemplate(template));
}
},[template]);
Now React will automatically run the function every time the value of template changes therefore, updates template.
For more information about useEffect ...
Refer React Documentation
Refer the useEffect API
In my react code, inside a component, I am fetching a value from session storage(inside useEffect hook). When console printed, it shows the value.
But inside the render(or return method), it does not have the value just fetched. Is there a delay while fetching from session storage?
Circumvented the problem after storing the same in state and fetching inside render!
let myValue = '';
useEffect(()=>{
myValue = sessionStorage.getItem("someKey");
},[]);
// In the return method
return {
<div>{myValue}</div>
}
Why does value fetched from session storage not available immediately in render?
The issue here is that you're expecting a variable value change to trigger a re-render. React doesn't work this way and you'll need another approach if you want to change a value and have it re-render:
Consider:
const [myValue, setMyValue] = useState('');
useEffect(()=>{
setMyValue(sessionStorage.getItem("someKey"));
},[]);
// In the return method
return {
<div>{myValue}</div>
}
No, both localStorage and sessionStorage calls are sync
You don't see the value in the render because the view is not re-rendered. You have to set a state, get a new props or force the render to see it.
How to force update in hooks
const [, updateState] = React.useState();
const forceUpdate = useCallback(() => updateState({}), []);
It's available immediately
return {
<div>{sessionStorage.getItem("someKey")}</div>
}
No, all sessionStorage calls are synchronous.