Category: react context

How to transfer data from context to component

Hello People. This article is about how to transfer data from context to component. As you know react context is very useful transferring data to components. Let us see this using an example code below.

hyderabad.json

{
  "html_attributions": [],
  "next_page_token": "some token",
  "results": [
    {
      "business_status": "OPERATIONAL",
      "geometry": {
        "location": {
          "lat": 17.499838,
          "lng": 78.588024
        },
        "viewport": {
          "northeast": {
            "lat": 17.6552887,
            "lng": 78.6768359
          },
          "southwest": {
            "lat": 17.4186855,
            "lng": 78.46588849999999
          }
        }
      },
      "icon": "https://maps.gstatic.com/mapfiles/place_api/icons/v1/png_71/lodging-71.png",
      "name": "XYZ Company",
      "opening_hours": {
        "open_now": true
      },
      "photos": 
         ["https://i.postimg.cc/ZRghDVkL/Screenshot-1961.png",],
      "place_id": "some place id 1",
      "rating": 5,
      "reference": "",
      "user_ratings_total": 832,
      "vicinity": "Banjara Hills, Hyderabad"
    }
   
  ],
  "status": "OK"
}
How to transfer data from context to component

Let us assume you have the above example data with you. The data contains information about restaurants. We can use that data in a restaurant app. And let us suppose you want to transfer this data to a component. We can do this by passing this data through a context. Before passing this data through a context, we need to transform the data so that it is more user friendly on the front end. We can do that by writing the following code.

restaurants.service

import { mocks } from "./mock";
import camelize from "camelize";

export const restaurantsRequest = (location) => {
  return new Promise((resolve, reject) => {
    const mock = mocks[location];
    if (!mock) {
      reject("not found");
    }
    resolve(mock);
  });
};

export const restaurantsTransform = ({ results = [] }) => {
  const mappedResults = results.map((restaurant) => {
    
    return {
      ...restaurant,
      address: restaurant.vicinity,
      isOpenNow: restaurant.opening_hours && restaurant.opening_hours.open_now,
      isClosedTemporarily: restaurant.business_status === "CLOSED_TEMPORARILY",
      photos: restaurant.photos
    };
  });

  return camelize(mappedResults);
};

We can store the response data coming from google locally. After that we can use this mock data anywhere in the app. Any component that requires it can have access to this data locally. since the data is coming from local storage, we need to mock a promise. After the promise gets accepted, we write a transform function that changes the data format in a more front end friendly manner. After that we can pass this data through context as follows.

restaurants.context

import React, { useState, useContext, createContext, useEffect } from "react";

import {
  restaurantsRequest,
  restaurantsTransform,
} from "./restaurants.service";

import { LocationContext } from "../location/location.context";

export const RestaurantsContext = createContext();

export const RestaurantsContextProvider = ({ children }) => {
  const [restaurants, setRestaurants] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);
  const { location } = useContext(LocationContext);

  const retrieveRestaurants = (loc) => {
    setIsLoading(true);
    setRestaurants([]);

    restaurantsRequest(loc)
      .then(restaurantsTransform)
      .then((results) => {
        setError(null);
        setIsLoading(false);
        setRestaurants(results);
      })
      .catch((err) => {
        setRestaurants([]);
        setIsLoading(false);
        setError(err);
      });
  };
  useEffect(() => {
    if (location) {
      const locationString = `${location.lat},${location.lng}`;
      retrieveRestaurants(locationString);
    }
  }, [location]);

  return (
    <RestaurantsContext.Provider
      value={{
        restaurants,
        isLoading,
        error,
      }}
    >
      {children}
    </RestaurantsContext.Provider>
  );
};

Now the data is present in the file restaurants.context. This data can be passed on to any component using the context provider. To clarify to you we are passing this data to a component “restaurant.info-card.component”. Let us see the code of this component.

restaurant.info-card.component.js

import React from "react";
import { SvgXml } from "react-native-svg";
import { View } from "react-native";

import { Favourite } from "../../../components/favourites/favourite.component";
import { Spacer } from "../../../components/spacer/spacer.component";
import { Text } from "../../../components/typography/text.component";
import star from "../../../../assets/star";
import open from "../../../../assets/open";

import {
  RestaurantCard,
  RestaurantCardCover,
  Info,
  Section,
  SectionEnd,
  Rating,
  Icon,
  Address,
} from "./restaurant-info-card.styles";

export const RestaurantInfoCard = ({ restaurant = {} }) => {
  const {
    name = "Some Restaurant",
    icon = "https://maps.gstatic.com/mapfiles/place_api/icons/v1/png_71/lodging-71.png",
    photos = [
      "https://www.foodiesfeed.com/wp-content/uploads/2019/06/top-view-for-box-of-2-burgers-home-made-600x899.jpg",
    ],
    address = "100 some random street",
    isOpenNow = true,
    rating = 4,
    isClosedTemporarily = true,
    placeId,
  } = restaurant;

  const ratingArray = Array.from(new Array(Math.floor(rating)));

  return (
    <RestaurantCard elevation={2}>
      <View>
        <Favourite restaurant={restaurant} />
        <RestaurantCardCover key={name} source={{ uri: photos[0] }} />
      </View>
      <Info>
        <Text variant="label">{name}</Text>
        <Section>
          <Rating>
            {ratingArray.map((_, i) => (
              <SvgXml
                key={`star-${placeId}-${i}`}
                xml={star}
                width={20}
                height={20}
              />
            ))}
          </Rating>
          <SectionEnd>
            {isClosedTemporarily && (
              <Text variant="error">CLOSED TEMPORARILY</Text>
            )}
            <Spacer position="left" size="large">
              {isOpenNow && <SvgXml xml={open} width={20} height={20} />}
            </Spacer>
            <Spacer position="left" size="large">
              <Icon source={{ uri: icon }} />
            </Spacer>
          </SectionEnd>
        </Section>
        <Address>{address}</Address>
      </Info>
    </RestaurantCard>
  );
};

As you can see from the code above, the data from context is not passed from context to the above component. But we import context in the parent component and pass this data as props from parent component to its child component. To clarify to you, let us see the code of parent component. It has the name restaurants.screen.

restaurants.screen.js

import React, { useContext, useState } from "react";
import { TouchableOpacity } from "react-native";
import styled from "styled-components/native";
import { ActivityIndicator, Colors } from "react-native-paper";

import { FadeInView } from "../../../components/animations/fade.animation";
import { SafeArea } from "../../../components/utility/safe-area.component";
import { Spacer } from "../../../components/spacer/spacer.component";
import { Text } from "../../../components/typography/text.component";
import { FavouritesBar } from "../../../components/favourites/favourites-bar.component";

import { LocationContext } from "../../../services/location/location.context";
import { RestaurantsContext } from "../../../services/restaurants/restaurants.context";
import { FavouritesContext } from "../../../services/favourites/favourites.context";

import { Search } from "../components/search.component";
import { RestaurantInfoCard } from "../components/restaurant-info-card.component";

import { RestaurantList } from "../components/restaurant-list.styles";

const Loading = styled(ActivityIndicator)`
  margin-left: -25px;
`;
const LoadingContainer = styled.View`
  position: absolute;
  top: 50%;
  left: 50%;
`;

export const RestaurantsScreen = ({ navigation }) => {
  const { error: locationError } = useContext(LocationContext);
  const { isLoading, restaurants, error } = useContext(RestaurantsContext);
  const { favourites } = useContext(FavouritesContext);
  const [isToggled, setIsToggled] = useState(false);
  const hasError = !!error || !!locationError;
  return (
    <SafeArea>
      {isLoading && (
        <LoadingContainer>
          <Loading size={50} animating={true} color={Colors.blue300} />
        </LoadingContainer>
      )}
      <Search
        isFavouritesToggled={isToggled}
        onFavouritesToggle={() => setIsToggled(!isToggled)}
      />
      {isToggled && (
        <FavouritesBar
          favourites={favourites}
          onNavigate={navigation.navigate}
        />
      )}
      {hasError && (
        <Spacer position="left" size="large">
          <Text variant="error">Something went wrong retrieving the data</Text>
        </Spacer>
      )}
      {!hasError && (
        <RestaurantList
          data={restaurants}
          renderItem={({ item }) => {
            return (
              <TouchableOpacity
                onPress={() =>
                  navigation.navigate("RestaurantDetail", {
                    restaurant: item,
                  })
                }
              >
                <Spacer position="bottom" size="large">
                  <FadeInView>
                    <RestaurantInfoCard restaurant={item} />
                  </FadeInView>
                </Spacer>
              </TouchableOpacity>
            );
          }}
          keyExtractor={(item) => item.name}
        />
      )}
    </SafeArea>
  );
};

As you can see in the above code, data is passed as props to the child component. The data already present in the child component becomes dummy now. Context data has the highest priority and it will be rendered the child component.

Hope this article on how to transfer data from context to component is useful to you. To know how to create a search bar for your mobile app, please read How to create a search bar in react native.

How to transform data from Google API

Hello People. This article explains you How to transform data from Google API. This could be useful to transform the data coming from API and render it on the frontend. Let us take example of a json file by the name hyderabad.json.

hyderabad.json

{
  "html_attributions": [],
  "next_page_token": "some token",
  "results": [
    {
      "business_status": "OPERATIONAL",
      "geometry": {
        "location": {
          "lat": 17.499838,
          "lng": 78.588024
        },
        "viewport": {
          "northeast": {
            "lat": 17.6552887,
            "lng": 78.6768359
          },
          "southwest": {
            "lat": 17.4186855,
            "lng": 78.46588849999999
          }
        }
      },
      "icon": "https://maps.gstatic.com/mapfiles/place_api/icons/v1/png_71/lodging-71.png",
      "name": "XYZ Company",
      "opening_hours": {
        "open_now": true
      },
      "photos": [
        {
          "height": 0,
          "html_attributions": [],
          "photo_reference": "",
          "width": 0
        }
      ],
      "place_id": "some place id 1",
      "rating": 5,
      "reference": "",
      "user_ratings_total": 832,
      "vicinity": "Banjara Hills, Hyderabad"
    }
   
  ],
  "status": "OK"
}

After getting the data from google, let us save it in a file called hyderabad.json. The above code is an example of a file coming from Google API when a developer makes an API request. In this case the developer uses his google API key and queries for restaurants in Hyderabad. Google API sends him the above the response. However the developer wants to transform the data so it is more user friendly on the front end. To clarify you better, the data contains a field called vicinity. Vicinity is not a very familiar terminology in mobile apps. The term address could be more user friendly. Also look at the term restaurant.opening_hours.open_now. We can replace this by the term isOpenNow. Similarly we can replace restaurant.business_status === “CLOSED_TEMPORARILY” by isClosedTemporarily and the with an answer of “yes” or “no”. We can achieve this by writing a code like this one as shown below.

How to transform data from Google API

restaurants.service.js

import { mocks} from "./mock";
import camelize from "camelize";

export const restaurantsRequest = (location) => {
  return new Promise((resolve, reject) => {
    const mock = mocks[location];
    if (!mock) {
      reject("not found");
    }
    resolve(mock);
  });
};

export const restaurantsTransform = ({ results = [] }) => {
  const mappedResults = results.map((restaurant) => {
   
    return {
      ...restaurant,
      address: restaurant.vicinity,
      isOpenNow: restaurant.opening_hours && restaurant.opening_hours.open_now,
      isClosedTemporarily: restaurant.business_status === "CLOSED_TEMPORARILY",
    };
  });

  return camelize(mappedResults);
};

Now let us look at the code. We can store the response data coming from google locally. After that we can use this mock data anywhere in the app. Any component that requires it can have access to this data locally. since the data is coming from local storage, we need to mock a promise. After the promise gets accepted, we write a transform function that changes the data format in a more front end friendly manner.

Hope this article on How to transform data from Google API is useful to you. To know how to create a search bar for your mobile app, please read How to create a search bar in react native.

How to create a map screen in react native

Hello People. This article discusses about how to create a map screen in react native. We can use map screen in the app to display our service providers. In this article let us take an example of a food delivery app that shows nearby restaurants on the map screen. Let us see the code of map screen using an example as below.

map.screen.js

import React, { useContext, useState, useEffect } from "react";
import MapView from "react-native-maps";
import styled from "styled-components/native";

import { LocationContext } from "../../../services/location/location.context";
import { RestaurantsContext } from "../../../services/restaurants/restaurants.context";

import { Search } from "../components/search.component";
import { MapCallout } from "../components/map-callout.component";

const Map = styled(MapView)`
  height: 100%;
  width: 100%;
`;

const RestaurantMap = ({ navigation }) => {
  const { location } = useContext(LocationContext);
  const { restaurants = [] } = useContext(RestaurantsContext);

  const [latDelta, setLatDelta] = useState(0);

  const { lat, lng, viewport } = location;

  useEffect(() => {
    const northeastLat = viewport.northeast.lat;
    const southwestLat = viewport.southwest.lat;

    setLatDelta(northeastLat - southwestLat);
  }, [location, viewport]);

  return (
    <>
      <Search />
      <Map
        region={{
          latitude: lat,
          longitude: lng,
          latitudeDelta: latDelta,
          longitudeDelta: 0.01,
        }}
      >
        {restaurants.map((restaurant) => {
          return (
            <MapView.Marker
              key={restaurant.name}
              title={restaurant.name}
              coordinate={{
                latitude: restaurant.geometry.location.lat,
                longitude: restaurant.geometry.location.lng,
              }}
            >
              <MapView.Callout
                onPress={() =>
                  navigation.navigate("RestaurantDetail", {
                    restaurant,
                  })
                }
              >
                <MapCallout restaurant={restaurant} />
              </MapView.Callout>
            </MapView.Marker>
          );
        })}
      </Map>
    </>
  );
};

export const MapScreen = ({ navigation }) => {
  const { location } = useContext(LocationContext);
  if (!location) {
    return (
      <Map
        region={{
          latitude: 0,
          longitude: 0,
        }}
      />
    );
  }
  return <RestaurantMap navigation={navigation} />;
};

As you can see, the map screen imports location context and retaurants context that contain data of locations and restaurants respectively. Map screen also imports search component and mapcallout components. Search component is basically a search bar that has functionality to search locations from the database or local data based on the search term. Map callout component is the UI that displays details of the searched restaurant like restaurant name, photo, rating etc.

How to create a map screen in react native

We create a function by the name RestaurantMap. This function uses location context and restaurant context. We can destructure locations and restaurants array from the context and use them here in this screen. Location contains the details latitude, longitude and viewport. Using the uesEffect hook, we set the initial viewport with northeast latitude and southwest latitude. After that we can display the resaurants. We can do this by using restaurants.map function. But if there is no location in the database, we can set the map region to 0,0 are any other lat, lng value.

Talking about Location context, it stores location data and you can import it in any component. This location context is importing locationRequest and locationTransform from the component location.service. Similarly we get data from restaurant context also. For example on location context, you can visit the link given in the next paragraph.

Hope this article on how to create a map screen in react native is useful to you. Please also visit How to create location context in react native.

How to create cart context in react native

Hello People. This article is about how to create cart context in react native. As you all know adding items to cart and removing items from cart is a very common feature in e-commerce, multi vendor app platforms and several others. In this article let us create a cart context in the case of multi vendor restaurant app.

Let’s see an example of a cart context using an example code.

cart.context.js

import React, { createContext, useState, useEffect, useContext } from "react";
import AsyncStorage from "@react-native-async-storage/async-storage";

import { AuthenticationContext } from "../authentication/authentication.context";

export const CartContext = createContext();

export const CartContextProvider = ({ children }) => {
  const { user } = useContext(AuthenticationContext);

  const [cart, setCart] = useState([]);
  const [restaurant, setRestaurant] = useState(null);

  const [sum, setSum] = useState(0);

  const saveCart = async (rst, crt, uid) => {
    try {
      const jsonValue = JSON.stringify({ restaurant: rst, cart: crt });
      await AsyncStorage.setItem(`@cart-${uid}`, jsonValue);
    } catch (e) {
      console.log("error storing", e);
    }
  };

  const loadCart = async (uid) => {
    try {
      const value = await AsyncStorage.getItem(`@cart-${uid}`);
      if (value !== null) {
        const { restaurant: rst, cart: crt } = JSON.parse(value);
        setRestaurant(rst);
        setCart(crt);
      }
    } catch (e) {
      console.log("error storing", e);
    }
  };

  useEffect(() => {
    if (user && user.uid) {
      loadCart(user.uid);
    }
  }, [user]);

  useEffect(() => {
    if (user && user.uid) {
      saveCart(restaurant, cart, user.uid);
    }
  }, [restaurant, cart, user]);

  useEffect(() => {
    if (!cart.length) {
      setSum(0);
      return;
    }
    const newSum = cart.reduce((acc, { price }) => {
      return (acc += price);
    }, 0);
    setSum(newSum);
  }, [cart]);

  const add = (item, rst) => {
    if (!restaurant || restaurant.placeId !== rst.placeId) {
      setRestaurant(rst);
      setCart([item]);
    } else {
      setCart([...cart, item]);
    }
  };

  const clear = () => {
    setCart([]);
    setRestaurant(null);
  };

  return (
    <CartContext.Provider
      value={{
        addToCart: add,
        clearCart: clear,
        restaurant,
        cart,
        sum,
      }}
    >
      {children}
    </CartContext.Provider>
  );
};

The first line of code must be very clear to you. Createcontext creates the context and useContext uses it. After that in the second line, AsyncStorage stores data locally. AuthenticationContext is imported in this file because user object comes from the authentication context. Link to the authentication context is at the end of this article.

How to create cart context in react native

We define the state variables cart, restaurant and sum to an empty array, null and zero respectively. This indicates empty cart, no restaurant chosen yet and no bill value yet. We create a function by the name saveCart. This function takes the arguments rst, crt and uid corresponding to restaurant, cart and user id. After that we create a jsonValue that contains rst and crt. Now we store this value in the asyncstorage of the user using setItem method. We use a try and catch method and console.log to catch errors.

Since we have stored the data in asyncstorage and saved the cart using saveCart function, let us now load the cart using loadCart function. This can be done by using the asyncstorage.getItem method. We use useEffect hook to render this component at the very beginning. Also w use useEffect hook for saveCart, setSum so that all these values are rendered at the very beginning. After that we also create functions like newSum, add, clear. The values generated by the functions add, clear are passes as values through the cartContext provider. Also restaurant, cart and sum are also passed through the cartContext.Provider. We can use these values in any component that requires them.

Hope this article is useful to you. After this read about How to create authentication context in expo

Navigation

× Contact Us