I have some issue. When I do to async fetch data (using axios for fetching) in the useEffect, and after I set responsed data to state, using a useState hook. And page render befor then I got response from server.
For demonstration this issue I have putted console.log for get current state, and I get 'undefined':
const [positions, setPositions] = useState([]);
useEffect(() => {
const fetchPositions = async () => {
const response = await EmployeeService.getEmployeePositions();
setPositions(response.data);
};
fetchPositions();
console.log('positions from state: ', positions); //undefined
}, []);
Method for fetching data from "EmployeeService":
getEmployeePositions(){
return axios.get(EMPLOYEE_API_BASE_URL + '/positions');
}
Thanks in advance, and best regards!
React needs to re-render to display the results.
Which means you need to capture the result on the subsequent re-render that is caused when you setState.
Move the console log outside of the useEffect
const [positions, setPositions] = useState([]);
useEffect(() => {
const fetchPositions = async () => {
const response = await EmployeeService.getEmployeePositions();
setPositions(response.data);
};
fetchPositions();
}, []);
console.log('positions from state: ', positions); // NOT UNDEFINED
React will always render once before you have data.
So you can catch it with a condition.
if (positions.length === 0) {
return null;
}
nothing wrong with your code, useEffect is always undefined because it read the first value of your rendered app.
To update state in useEffect put paramater on the array [] but in your case it will cause an infinity loop.
try logging inside the async function instead
const [positions, setPositions] = useState([]);
useEffect(() => {
const fetchPositions = async () => {
const response = await EmployeeService.getEmployeePositions();
setPositions(response.data);
console.log('data from response: ', response);
};
fetchPositions();
}, []);
or do it like this
const [positions, setPositions] = useState([]);
useEffect(() => {
const fetchPositions = async () => {
const response = await EmployeeService.getEmployeePositions();
setPositions(response.data);
console.log('data from response: ', response);
};
if((positions ?? []).length == 0){
fetchPositions();
console.log('this is position state before fetch~>',positions)
} else{
console.log('this is position state after fetch~>',positions)
}
}, [positions]);
Related
I get data from backend and set to my state in componentdidmount but value not set after log state
const [tasks, setTasks] = useState([]);
const getTasks = async () => {
const getTodoInformation = {
email: localStorage.getItem("tokenEmail"),
};
if (getTodoInformation.email) {
const response = await axios.post(
"http://localhost:9000/api/todo/get",
getTodoInformation
);
setTasks(response.data.data);
}
};
useEffect(() => {
getTasks();
console.log(tasks);
}, []);
My tasks is empty when i log it
So the title and the question itself are actually two questions.
React Hook useEffect has a missing dependency: 'tasks'. Either includes it or remove the dependency array
That's because you include a state (i.e. tasks) in the useEffect hook. And React is basically asking you, "Do you mean run console.log(tasks) every time tasks is updated?". Because what you are doing is run the useEffect hook once and only once.
And for your "actual" question
value not set after log state
In short, states are set in async manner in React. That means tasks is not necessary immediately updated right after you call setTasks. See #JBallin comment for details.
const [tasks, setTasks] = useState([]);
useEffect(() => {
setTimeout(async () => {
const getTodoInformation = {
email: localStorage.getItem("tokenEmail"),
};
if (getTodoInformation.email) {
const response = await axios.post(
"http://localhost:9000/api/todo/get",
getTodoInformation
);
setTasks(response.data.data);
}
}, 1000);
console.log(tasks);
}, []);
The main problem is that useEffect -> is a sync method, getTasks() is asynchronous, and useEffect only works once when your component mounts. Shortly speaking, you got your data from the backend after useEffect worked.
For example, if you will add one more useEffect
useEffect(() => {
console.log(tasks);
}, [tasks]);
You will see log, after your data will have changed.
You can use self-calling async function inside useEffect as shown here:
const [tasks, setTasks] = useState([]);
const getTasks = async () => {
const getTodoInformation = {
email: localStorage.getItem("tokenEmail"),
};
if (getTodoInformation.email) {
const response = await axios.post(
"http://localhost:9000/api/todo/get",
getTodoInformation
);
return response.data.data;
}
};
useEffect(() => {
(async () => {
const tasks = await getTasks();
setTasks(tasks);
})();
console.log(tasks);
}, [tasks]);
I want to get real time bitcoin information but datas not coming. I get this error = React Hook useEffect has a missing dependency: 'coinData'. Either include it or remove the dependency array
const [coinData,setCoinData] = useState([]);
useEffect(() => {
const getData = async () =>{
const baseURL = "https://api.coingecko.com/api/v3/coins/bitcoin?tickers=true&market_data=true&community_data=true&developer_data=true&sparkline=true"
const response = await axios(baseURL)
setCoinData(response);
console.log(coinData)
}
getData();
}, []);
The error is because you're using coinData (state) inside useEffect.
If you add coindData to the dependencies array, you'll get an infinite loop.
To log the response use console.log(response), not console.log(coinData).
useEffect(() => {
const getData = async () =>{
const baseURL = "https://api.coingecko.com/api/v3/coins/bitcoin?tickers=true&market_data=true&community_data=true&developer_data=true&sparkline=true"
const response = await axios(baseURL)
setCoinData(response);
console.log(response);
}
getData();
}, []);
I am trying to setState from useEffect but it comes back as undefined and I am unable to use it in other components. I am able to console log the state though and it displays the object fine. Thanks.
function App() {
const [tokens, setTokens] = useState();
console.log(tokens)
useEffect(() => {
async function init() {
await Moralis.initPlugins();
await Moralis.enable();
await listAvailableTokens();
}
init();
// token info from 1inch
const listAvailableTokens = async () => {
const result = await Moralis.Plugins.oneInch.getSupportedTokens({
chain: "eth", // The blockchain you want to use (eth/bsc/polygon)
});
const tokensObject = result.tokens;
console.log(tokensObject)
setTokens(tokensObject);
};
}, []);
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I am trying to fetch some data from google's firestore in an useEffect, and saving it in useState variable
useEffect(() => {
const fetchFirst = async () => {
...
// setting the new found data in a useState
setData1(data1)
}
fetchFirst()
}, [])
Now, I want to fetch some other data from firestore, but this data requires some information from previous fetched (fetchFirst) data. I tried to do this but does not work
useEffect(() => {
const fetchFirst = async () => {
...
// setting the new found data in a useState
setData1(data1)
}
const fetchSecond = async (data1) => {
...
// setting the new found data in a useState
setData2(data2)
}
fetchFirst()
fetchSecond(data1)
}, [])
My first fetch works completely fine, but when my code reaches the second fetch, the input data (data1) is null. Can someone please help me figure it out. Thanks
If your using async you should wait, with the await keyword, for the first fetching to finish, then use its result in the fetchSecond:
useEffect(() => {
const fetchFirst = async (): SomeData => {
const data = await fetch(...);
return data;
};
const fetchSecond = async (data: SomeData) => {
await fetch(...);
};
const fetchAllData = async () => {
const data = await fetchFirst();
await fetchSecond();
};
fetchAllData();
}, []);
Both function are async. You need to call fetchSecond when data1 value changes:
useEffect(() => {
const fetchFirst = async () => {
...
// setting the new found data in a useState
setData1(data1)
}
fetchFirst()
}, []);
useEffect(() => {
const fetchSecond = async (data1) => {
...
// setting the new found data in a useState
setData2(data2)
}
fetchSecond(data1)
}, [data1]);
Or call fetchSecond inside then block
useEffect(() => {
const fetchFirst = async () => {
...
// setting the new found data in a useState
setData1(data1);
return data1 //--> return data value
}
const fetchSecond = async (data1) => {
...
// setting the new found data in a useState
setData2(data2)
}
fetchFirst().then(data => fetchSecond(data));
}, []);
You can simply call your second inside your first function call and pass data that you're setting in the state rather than passing state data.
useEffect(() => {
const fetchFirst = async () => {
...
// calling the function with new found data
fetchSecond(data1)
// setting the new found data in a useState
setData1(data1)
}
const fetchSecond = async (data1) => {
...
// setting the new found data in a useState
setData2(data2)
}
fetchFirst()
}, [])
I'm new to hooks and recently started using hooks in my React Native projects.
I'm building a simple todo app using the AsyncStorage. First I initialize initial data and setData state using useState hook:
const [data, setData] = useState([]);
There are two textInput and submit button that I use to save data to AsyncStorage. Here is the saveData function:
const saveData = async () => {
const arrData = [{ name: 'vikrant', phone: 123456 }]; // [{ name, phone}] from the textInput
const storedData = await AsyncStorage.getItem('user');
const storedDataParsed = JSON.parse(storedData);
let newData = [];
if (storedData === null) {
// save
await AsyncStorage.setItem('user', JSON.stringify(arrData));
} else {
newData = [...storedDataParsed, user];
await AsyncStorage.setItem('user', JSON.stringify(newData));
}
setName('');
setPhone('');
Keyboard.dismiss();
};
Now, I'm using useEffect to get data from the AsyncStorage and setting it to the data state. I'm using data to render the text in the screen.
useEffect(() => {
retrieveData();
}, [data]);
const retrieveData = async () => {
try {
const valueString = await AsyncStorage.getItem('user');
const value = JSON.parse(valueString);
setData(value);
} catch (error) {
console.log(error);
}
};
I'm using [data] in useEffect since I want to re-render my component each time data changes i.e. each time I save data in AsyncStorage. But this is causing infinite loop as setData causes useEffect to run infinitely.
If I remove data from the [] it doesn't loop but my data in render is one step behind. So whenever I save data it doesn't show the current data but the previous one.
Any explanation of what I am doing wrong here and how can i fix this?
Thanks.
As already mentioned by you, the infinite loop is due to thefact that you pass data as a dependency to useEffect and also set in inside the function called in useEffect.
The solution here is to not use useEffect and instead setData whenever you are setting value in AsyncStorage
const saveData = async () => {
const arrData = [{ name: 'vikrant', phone: 123456 }]; // [{ name, phone}] from the textInput
const storedData = await AsyncStorage.getItem('user');
const storedDataParsed = JSON.parse(storedData);
let newData = [];
if (storedData === null) {
// save
await AsyncStorage.setItem('user', JSON.stringify(arrData));
} else {
newData = [...storedDataParsed, user];
await AsyncStorage.setItem('user', JSON.stringify(newData));
}
setName('');
setPhone('');
setData(newData);
Keyboard.dismiss();
};
Just add a conditional flag, retrieve to wrap async storage, retrieveData(), calls.
Also in the context of "saving data" I would probably just separate async storage-ish logic with state logic. Current saveData is polluted with both state and async storage logic.
Something like:
const [retrieve, setRetrieve] = useState(false);
// Pure AsyncStorage context
const saveData = async () => {
...
if (storedData === null) {
await AsyncStorage.setItem('user', JSON.stringify(arrData));
} else {
newData = [...storedDataParsed, user];
await AsyncStorage.setItem('user', JSON.stringify(newData));
}
// XXX: Removed state logic, call it somewhere else.
};
const someHandler = async () => {
await saveData();
setRetrieve(true); // to signal effect to call retrieveData()
}
Then the goal of the effect is just to run retrieveData() once saving is done.
const [data, setData] = useState([]);
useEffect(() => {
const retrieveData = async () => {
try {
const valueString = await AsyncStorage.getItem('user');
const value = JSON.parse(valueString);
// Other set states
setData(value);
} catch (error) {
console.log(error);
}
};
// Retrieve if has new data
if (retrieve)
retrieveData();
setRetrieve(false);
}
}, [retrieve]);