So, I've started studying React by doing class components. There, as far as I understood what I was doing, if I had a
this.state = {
isLoading: false,
dataToRender: [],
}
this.setState({ isLoading: true }, async () => {
const data = await fetchData();
this.setState({ dataToRender: data , isLoading: false });
})
const message => <p>loading...</p>
if (isLoading) return message();
return (
dataToRender.map
)
for displaying a "loading" message whenever I call an API for new data, I could know that the setState "queue" would be executed in an order. The outer setState would receive a first state change on the first parameter and a function to execute right after it as the second parameter.
The problem is that I'm having a bit of difficulty wrapping my head around ways to achieve this with hooks. I'm assuming doing
const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState([]);
setLoading(async () => {
setLoading(true)
const data = await fetchData()
setData(data);
return false;
})
wouldn't work, right? I feel like the overall logic of building this kind of component logic may be different when using hooks somehow... If anyone could at least point me to concept direction it would be nice. Thanks! :)
CodePudding user response:
There's no callback with the dispatch function of useState
.
const fn = async () => {
setIsLoading(true)
const data = await fetchData()
setData(data)
setIsLoading(false)
})
The above function is normally invoked upon an event such as onClick
or useEffect
.
CodePudding user response:
The functions passed as a useState
state update function are treated as synchronous functions, so you are effectively saving the implicitly returned Promise object into state.
What you should do is factor the asynchronous logic into a function that is called from an event handler, like onClick
, or is called in a component lifecycle, like useEffect
.
const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState([]);
const asyncCall = async () => {
setLoading(true);
try {
const data = await fetchData();
setData(data);
} catch(error) {
// handle any errors, logging, etc...
} finally {
setLoading(false);
}
};
This will call/enqueue each state update in the order they are enqueued. You should also surround any asynchronous logic in a try/catch
block so you can handle any rejected promises, clear the loading state in a finally
so that regardless of resolved/rejected promises, when the code completes it resets the loading state.
CodePudding user response:
depending on Kent React normally batches these calls so you only get a single re-render, but it's unable to do this in an asynchronous callback (like our promise success and error handlers). You can use object for value of useState or use useReducer.
const [state,setState]=useState({isLoading:false,success:false,isError:false,data:[]})
then setting those property on each status.