I have the below code which works really well, but I can't see to handle the fact that 'NOTHING' is displayed with a flicker as the state changes / there is re-rendering before the data is shown.
How can I wait until the state is updated and only show the spinning loader until all the hooks have executed / the final state is recognized final render have taken place?
A note that item.something
is originally undefined
before useEffect hence the need to check before returning.
Does there need to be an initial state set (so that item.something !== undefined
, and if so, how would I do that?
Is it possibly something like const [item, setItem] = useState('Somehting here')
?
import { useEffect, useState } from 'react';
import { useParams, useSearchParams, useNavigate } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import { getItem } from '../features/itemSlice';
import { toast } from 'react-toastify';
import Spinner from '../components/Spinner';
function Items() {
const [searchParams, setSearchParams] = useSearchParams();
const itemObject = searchParams.get(`item`);
const { item, isLoading, isError, message } = useSelector((state) => state.task);
const dispatch = useDispatch();
useEffect(() => {
if (isError) {
toast.error(message);
}
dispatch(getItem(itemObject));
// eslint-disable-next-line
}, [isError, message, itemObject]);
if (isLoading) {
return <Spinner />;
}
if (isError) {
return <h3>Error</h3>;
}
return (
<>
<div>
{!item.something ? ( //How to refactor here(?) so that nothing is rendered if no data and await result of useEffect hook
<p>NOTHING</p>
) : (
item.something.map((element, index) => {
return element.body ? <p key={index}>{element.somethingElse}</p> : <p key={index}>Truly Nothing This Time</p>;
})
)}
</div>
</>
);
}
export default Items;
CodePudding user response:
Should be able to accomplish this by adding another condition in your spinner return that check that something
is available.
import { useEffect, useState } from 'react';
import { useParams, useSearchParams, useNavigate } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import { getItem } from '../features/itemSlice';
import { toast } from 'react-toastify';
import Spinner from '../components/Spinner';
function Items() {
const [searchParams, setSearchParams] = useSearchParams();
const itemObject = searchParams.get(`item`);
const { item, isLoading, isError, message } = useSelector((state) => state.task);
const dispatch = useDispatch();
useEffect(() => {
if (isError) {
toast.error(message);
}
dispatch(getItem(itemObject));
// eslint-disable-next-line
}, [isError, message, itemObject]);
// move this to the top because in error state `item.something` will likely be falsy
if (isError) {
return <h3>Error</h3>;
}
if (isLoading || !item.something) { // renders spinner when `item.something` is undefined (or any falsy value)
return <Spinner />;
}
return (
<>
<div>
{item.something.map((element, index) => {
return element.body ? <p key={index}>{element.somethingElse}</p> : <p key={index}>Truly Nothing This Time</p>;
})
)}
</div>
</>
);
}