Search code examples
reactjsfirebasereact-nativereduxredux-actions

How to show activity indicator until all data from firestore are fetched and displayed in react native using redux


I am Using FireBase as a Database in a react-native app using Redux. I want to Show an Activity Indicator until the data is been fetched. my Redux action is:

export const fetchproducts=()=>{
    return  async dispatch=>{
       const items = []
       const db = firebase.firestore();
       db.collection("Shops").collection('products').get().then((querySnapshot)=> {
           querySnapshot.forEach((doc,i)=> {  
              items.push(new Product(
                  doc.id, 
                  doc.data().name, 
                  doc.data().description, 
                  doc.data().price, 
               ))
           });   
           dispatch({
              type:SET_PRODUCTS,
              products:items
           })
   }).catch((err)=>{
         throw err
      })
  }
 }

My React Native js code is:

const ProductsOverviewScreen = props => {
      const [isLoading,setIsLoading]=useState(false)
      const [isRefreshing,setIsRefreshing]=useState(false)
      const allshops = useSelector(state => state.shops.allshops);
      const [error,setError]=useState()
      const products = useSelector(state => state.products.availableProducts);
      const dispatch = useDispatch();

      const loadProducts=useCallback( async ()=>{
            setError(null)
            setIsLoading(true)
            try{
                await dispatch(productActons.fetchproducts())
            }catch(err){
                setError(err.message)
            }
            setIsLoading(false)
      },[dispatch,setIsLoading,setError])

      useEffect(()=>{
          const willFocusSub=props.navigation.addListener('willFocus',()=>{
          loadProducts()
      })
       return ()=>{
         willFocusSub.remove()
       }
       },[loadProducts])


      useEffect(()=>{
         loadProducts()
      },[dispatch,loadProducts])

    if(error)
      {
       return <View style={{flex:1,alignItems:'center',justifyContent:'center'}}>
                 <Text>An error Occured </Text>
                 <Button title="Try Again" onPress={loadProducts} color={Colors.primary}></Button>
              </View>
      }  

     if(isLoading){
         return <View style={{flex:1,alignItems:'center',justifyContent:'center'}}>
                    <ActivityIndicator size="large" color={Colors.primary}/>
                </View>
      }

     if(!isLoading&&products.length===0)
         {
          return <View style={{flex:1,alignItems:'center',justifyContent:'center'}}>
                     <Text>No Products</Text></View>
         }

      return (
              <View>
                   <FlatList
                    horizontal={true}   
                    data={products}
                    keyExtractor={item => item.id}
                    renderItem={itemData => (
                                   <ProductItem
                                       image={itemData.item.id}
                                       title={itemData.item.name}
                                       price={itemData.item.price}
                                       onSelect={() => {
                                      selectItemHandler(itemData.item.id, itemData.item.title);
                                       }}
                                       >
                                      </ProductItem>
                )}
                />
          </View>

The out put shows 'No Products' First and then shows the product,instead of showing the activity indicator and shows the products


Solution

  • Change

    if(isLoading){
         return <View style={{flex:1,alignItems:'center',justifyContent:'center'}}>
                    <ActivityIndicator size="large" color={Colors.primary}/>
                </View>
      }
    
     if(!isLoading&&products.length===0)
         {
          return <View style={{flex:1,alignItems:'center',justifyContent:'center'}}>
                     <Text>No Products</Text></View>
         }
    

    to

    if(!isLoading && products.length===0){
             return <View style={{flex:1,alignItems:'center',justifyContent:'center'}}>
                        <ActivityIndicator size="large" color={Colors.primary}/>
                    </View>
          }
    
         if(isLoading&&products.length===0)
             {
              return <View style={{flex:1,alignItems:'center',justifyContent:'center'}}>
                         <Text>No Products</Text></View>
             }
    

    Hope this helps!