Reputation: 693
When using flags in redux state and class-based components, life is good. You start your API calls in componentWillMount
and by the time the component is mounted and the render()
function runs, you have your flags set correctly in redux, meaning no flash of unwanted content (FUC).
That is well, but we are using functional components now. In that case, we run API calls through useEffect(), meaning we set the flags in redux only on second render. In the case of a simple component:
function SimpleComponent() {
const isLoading = useSelector(selectIsLoading);
const dispatch = useDispatch();
useEffect(() => {
dispatch(startApiRequest());
},[dispatch]);
if (isLoading) {
return <LoadingComponent />;
}
return <ContentThatWillBreakIfApiCallIsNotFinished />;
}
The behaviour of this code is as follows:
render 1: isLoading is false, you show broken content.
after render 1: useEffect runs, sets isLoading to true
render 2: isLoading is true, you no longer show broken content
A simple solution is to init the store with isLoading set to true. That means that you will have to make sure to always return it to true when exiting components. This can lead to bugs if the same flag is used in multiple components. It is not an ideal solution.
With redux-thunk, we can use a custom hook that has internal isLoading flag and not set the flag in redux. Something like:
const apiCallWithLoadingIndicator = () => {
const [isLoading, setIsLoading] = useState(true);
const dispatch = useDispatch();
useEffect(() => {
(async () => {
await dispatch(asyncThunkReturningPromise());
setIsLoading(false);
})()
}, [setIsLoading, dispatch]);
return isLoading;
}
There doesn't seem to be a simple way of achieving this with redux-saga, where generators are used instead of promises. What is the best practice for handling loading flags with functional components in redux-saga?
Upvotes: 0
Views: 775
Reputation: 44136
Generally: componentWillMount
has been deprecated for years and will probably be removed in React 18 - you should not be using that in class components either.
That said, usually it helps to just start off the initial state with something like a "uninitialized" state value that tells you that, while it is not loading, it also hasn't even started doing anything yet and to handle that the same as "loading" in your component.
Upvotes: 2