<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Victor Olufade</title>
    <description>The latest articles on DEV Community by Victor Olufade (@victor_olufade_241a02b9b0).</description>
    <link>https://dev.to/victor_olufade_241a02b9b0</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1738292%2F83e0ab04-91d6-4c5a-b0ff-b2fc0395a71f.png</url>
      <title>DEV Community: Victor Olufade</title>
      <link>https://dev.to/victor_olufade_241a02b9b0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/victor_olufade_241a02b9b0"/>
    <language>en</language>
    <item>
      <title>Draw your custom polylines for directions on react-native-maps with Google Maps' Routes API and handle rerouting.</title>
      <dc:creator>Victor Olufade</dc:creator>
      <pubDate>Thu, 07 Aug 2025 10:38:12 +0000</pubDate>
      <link>https://dev.to/victor_olufade_241a02b9b0/draw-your-custom-polylines-for-directions-on-react-native-maps-with-google-maps-routes-api-and-1fj4</link>
      <guid>https://dev.to/victor_olufade_241a02b9b0/draw-your-custom-polylines-for-directions-on-react-native-maps-with-google-maps-routes-api-and-1fj4</guid>
      <description>&lt;p&gt;While working on a carpooling application over the past months using react-native, I had to use react-native-maps and react-native-maps-directions for map views and display of directions between locations.&lt;/p&gt;

&lt;p&gt;Under the hood react-native-maps-directions used Google's directions api to display polylines on the map. By Mar 1, 2025, Google decided to move the Directions API to legacy status and this meant Google Map apiKeys obtained after this date would no longer have access to the Directions API.&lt;/p&gt;

&lt;p&gt;Unfortunately I was utilizing a temporary apiKey before that date. By the time a billed key was provided, I could no longer utilize the react-native-maps-directions library. Google then replaced the Directions API with Routes API. To solve the problem, I had to write a custom hook that used the Routes API and the "@mapbox/polyline" library.&lt;/p&gt;

&lt;p&gt;The implementation is shared here. This is not necessarily in the most optimized state. You can further customize as you deem fit. But this works and even has a rerouting logic integrated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useEffect, useRef } from "react";
import { Polyline, LatLng } from "react-native-maps";
import polyline from "@mapbox/polyline";
import { theme } from "@src/theme/theme";
import { scale } from "react-native-size-matters";
import { useDebounce } from "use-debounce";
import { convertSecondsToMinutes } from "@src/utils/general";
import { haversineDistance } from "@src/utils/maps";

interface MapWithRoutesProps {
  origin: LatLng;
  destination: LatLng;
  apiKey: string;
  strokeColor?: string;
  strokeWidth?: number;
  refetchLocation?: LatLng | undefined;
  updateRouteInfoThreshold?: number; // Distance threshold in meters to trigger reroute
  onRouteReady?: (coords: LatLng[]) =&amp;gt; void;
}

interface RouteResponse {
  routes?: {
    polyline: {
      encodedPolyline: string;
    };
    distanceMeters: number;
    duration: string;
  }[];
}

const UseMapWithRoutes = ({
  origin,
  destination,
  apiKey,
  strokeColor = theme?.colors?.screens?.mapScreen?.directionsStroke,
  strokeWidth = scale(5),
  refetchLocation,
  updateRouteInfoThreshold = 100, // Default threshold of 50 meters
  onRouteReady,
}: MapWithRoutesProps) =&amp;gt; {
  const [polylineCoordinates, setPolylineCoordinates] = useState&amp;lt;LatLng[]&amp;gt;([]);
  const [distanceTimeObj, setDistanceTimeObj] = useState({
    distanceMeters: 0 as number | undefined,
    duration: "",
  });

  const [justSetPolyline, setJustSetPolyline] = useState(false)
  const triggerSetPolyline = (bool: boolean) =&amp;gt;
    setJustSetPolyline((prev) =&amp;gt; bool);

  const [refetchNow, setRefetchNow] = useState(false);
  const triggerImmediateRefetch = (bool: boolean) =&amp;gt;
    setRefetchNow((prev) =&amp;gt; bool);

  const isRerouting = useRef(false);

  const checkDeviation = (
    currentLocation: LatLng,
    polylineCoords: LatLng[]
  ) =&amp;gt; {
    if (!polylineCoords || polylineCoords.length === 0) return false;

    // Find the closest point on the polyline to the current location
    const closestPointDistance = Math.min(
      ...polylineCoords.map((point) =&amp;gt;
        haversineDistance(currentLocation, point)
      )
    );

    // Check if the distance exceeds the threshold
    return closestPointDistance &amp;gt; updateRouteInfoThreshold;
  };

  const handleReroute = async (currentLocation: LatLng) =&amp;gt; {
    if (isRerouting.current) return; // Prevent multiple reroute requests
    isRerouting.current = true;

    try {
      await fetchRoutes(currentLocation, {
        latitude: destination?.latitude,
        longitude: destination?.longitude,
      });
    } finally {
      isRerouting.current = false;
    }
  };

  const fetchRoutes = async (
    start: LatLng,
    end: LatLng,
    refetchDistance?: boolean
  ) =&amp;gt; {
    console.log("called fetchRoutes?&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;");

    if (!start || !end) {
      return;
    }
    try {
      const response = await fetch(
        `https://routes.googleapis.com/directions/v2:computeRoutes?key=${apiKey}`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            "X-Goog-FieldMask":
              "routes.polyline.encodedPolyline,routes.distanceMeters,routes.duration",
          },
          body: JSON.stringify({
            origin: {
              location: {
                latLng: {
                  latitude: start.latitude,
                  longitude: start.longitude,
                },
              },
            },
            destination: {
              location: {
                latLng: {
                  latitude: end.latitude,
                  longitude: end.longitude,
                },
              },
            },
            travelMode: "DRIVE",
            routingPreference: "TRAFFIC_AWARE",
          }),
        }
      );

      const data: RouteResponse = await response.json();

      if (!data || !data?.routes) return;

      if (refetchDistance === true) {
        setDistanceTimeObj((prev) =&amp;gt; ({
          ...prev,
          distanceMeters:
            data.routes![0].distanceMeters !== undefined
              ? Math.round(data.routes![0].distanceMeters / 1000)
              : 0,
          duration: convertSecondsToMinutes(data.routes![0].duration),
        }));
        return;
      }

      if (data.routes[0].polyline.encodedPolyline) {
        const encodedPolyline = data.routes[0].polyline.encodedPolyline;
        const decodedCoordinates = decodePolyline(encodedPolyline);
        setPolylineCoordinates(decodedCoordinates);
        triggerSetPolyline(true)
        data.routes &amp;amp;&amp;amp; data.routes?.length &amp;gt; 0
          ? setDistanceTimeObj((prev) =&amp;gt; ({
              ...prev,
              distanceMeters:
                data.routes![0].distanceMeters !== undefined
                  ? Math.round(data.routes![0].distanceMeters / 1000)
                  : undefined,
              duration: convertSecondsToMinutes(data.routes![0].duration),
            }))
          : null;
        if (onRouteReady) onRouteReady?.(decodedCoordinates);
        return decodedCoordinates;
      }
    } catch (error) {
      console.error("Error fetching routes:", error);
    }
  };

  useEffect(() =&amp;gt; {
    if (
      destination?.latitude &amp;amp;&amp;amp;
      origin?.latitude &amp;amp;&amp;amp;
      (!polylineCoordinates || polylineCoordinates.length === 0)
    ) {
      fetchRoutes(
        { latitude: origin?.latitude, longitude: origin?.longitude },
        {
          latitude: destination?.latitude,
          longitude: destination?.longitude,
        }
      );
    }

    if (destination?.latitude &amp;amp;&amp;amp; origin?.latitude &amp;amp;&amp;amp; refetchNow === true) {
      triggerImmediateRefetch(false);
      fetchRoutes(
        { latitude: origin?.latitude, longitude: origin?.longitude },
        {
          latitude: destination?.latitude,
          longitude: destination?.longitude,
        }
      );
    }
  }, [
    destination?.latitude,
    origin?.latitude,
    polylineCoordinates?.length,
    refetchNow,
  ]);

  // Monitor driver location for deviation
  useEffect(() =&amp;gt; { 
    if (
      refetchLocation?.latitude &amp;amp;&amp;amp;
      destination?.latitude &amp;amp;&amp;amp;
      polylineCoordinates?.length &amp;gt; 0
    ) {
      const hasDeviated = checkDeviation(refetchLocation, polylineCoordinates);
      if (hasDeviated) {
        handleReroute(refetchLocation);
      }
    }
  }, [refetchLocation?.latitude, polylineCoordinates?.length]);

  const decodePolyline = (encoded: string): LatLng[] =&amp;gt; {
    return polyline
      .decode(encoded)
      .map((point: any) =&amp;gt; ({ latitude: point[0], longitude: point[1] }));
  };

  const returnPolyLine = () =&amp;gt; {
    if (polylineCoordinates &amp;amp;&amp;amp; polylineCoordinates.length &amp;gt; 0) {
      return (
        &amp;lt;Polyline
          coordinates={polylineCoordinates}
          strokeColor={strokeColor}
          strokeWidth={strokeWidth}
        /&amp;gt;
      );
    }
    return null;
  };

  return {
    fetchRoutes,
    returnPolyLine,
    triggerImmediateRefetch,
    triggerSetPolyline,
    justSetPolyline,
    distanceTimeObj,
  };
};

export default UseMapWithRoutes;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then reuse the Component as shown here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const {
    returnPolyLine,
    distanceTimeObj,
    justSetPolyline,
    triggerSetPolyline,
  } = UseMapWithRoutes({
    origin: mapMarkers[0],
    destination: mapMarkers[1],
    apiKey: GOOGLE_MAPS_API_KEY,
    refetchLocation: defaultLocation,
    onRouteReady: handleMapDirectionsReady,
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The returnPolyline function can then be used within your map view as in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; &amp;lt;StyledMapView
            ref={models.mapRef}
            showsCompass={false}
            showsUserLocation={true}
            onUserLocationChange={operations.handleUserLocationChange}
            showsMyLocationButton={false}
            provider={PROVIDER_GOOGLE}
            customMapStyle={mapStyle}
            onRegionChangeComplete={operations.onregionChangeComplete}
          &amp;gt;
            {renderMapMarkers()}
            &amp;lt;MovingCarMarker
              ref={models?.carMarkerRef}
              defaultLocation={models?.defaultLocation}
            /&amp;gt;
            {operations?.returnPolyLine()}
          &amp;lt;/StyledMapView&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I really hope this helps other developers who may be having a similar challenge.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>typescript</category>
      <category>react</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Animating Custom Marker Motion On React-Native-Maps With Reanimated</title>
      <dc:creator>Victor Olufade</dc:creator>
      <pubDate>Sat, 05 Jul 2025 11:08:30 +0000</pubDate>
      <link>https://dev.to/victor_olufade_241a02b9b0/animating-custom-marker-motion-on-react-native-maps-with-reanimated-d58</link>
      <guid>https://dev.to/victor_olufade_241a02b9b0/animating-custom-marker-motion-on-react-native-maps-with-reanimated-d58</guid>
      <description>&lt;p&gt;If you have worked with React-Native in building a ride-hailing/Carpooling app or just any app that would require you to animate a marker(your custom image) on the map by coordinates, then you might have encountered the problems I did while building a carpooling app recently.&lt;/p&gt;

&lt;p&gt;My initial set-up required me to use the onUserLocationChange prop on the MapView from react-native-maps to animate the custom marker as illustrated here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { operations, models } = useTripsMapScreen({navigation, rider_id });

//In the useTripMapsScreen hook
const animateMarker = (newCoordinate: LatLng) =&amp;gt; {
  if (Platform.OS == 'android') {
    if (animatedMarkerRef.current) {
      animatedMarkerRef.current.animateMarkerToCoordinate(newCoordinate, 500);
    }
  } else {
    animatedMarkerCoord
      .timing({
        duration: 500,
        useNativeDriver: true,
        latitude: newCoordinate.latitude,
        longitude: newCoordinate.longitude,
      })
      .start();
  }
};

const handleUserLocationChange = ({
  nativeEvent: {coordinate},
}: UserLocationChangeEvent) =&amp;gt; {
  const newUserLocation = {
    coords: {
      latitude: coordinate?.latitude as number,
      longitude: coordinate?.longitude as number,
      heading: coordinate?.heading ?? 0,
    },
  };

  setUserLocation(newUserLocation);
  animateMarker({
    latitude: coordinate?.latitude,
    longitude: coordinate?.longitude,
  });
};
// end of useTripsMapScreen

&amp;lt;StyledMapView
  ref={models.mapRef}
  showsCompass={false}
  showsUserLocation={true}
  onUserLocationChange={operations.handleUserLocationChange}
  showsMyLocationButton={false}
  provider={PROVIDER_GOOGLE}
  customMapStyle={mapStyle}&amp;gt;
  {renderMapMarkers()}
  &amp;lt;Marker.Animated
    ref={models.animatedMarkerRef}
    coordinate={models.animatedMarkerCoord}&amp;gt;
    &amp;lt;Image
      source={carmaps}
      style={{
        width: 40,
        height: 40,
        transform: [{rotate: `${models.heading}deg`}],
      }}
      resizeMode="contain"
    /&amp;gt;
  &amp;lt;/Marker.Animated&amp;gt;
  &amp;lt;MapViewDirections
    origin={models.mapMarkers[0]}
    destination={models.mapMarkers[1]}
    apikey={GOOGLE_MAPS_API_KEY}
    strokeColor={theme?.colors?.screens?.mapScreen?.directionsStroke}
    strokeWidth={scale(5)}
    onReady={operations.handleMapDirectionsReady}
  /&amp;gt;
&amp;lt;/StyledMapView&amp;gt;;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This set-up worked perfectly on Android devices, but on iOS devices it behaved very strangely irrespective of whether I used the native driver or not. The marker, in my case a car image in png, would vibrate vigorously as it moved. I just could not get it to move smoothly.&lt;/p&gt;

&lt;p&gt;After so much frustration, I had to look for a solution with react-native-reanimated. Under the hood react-native-maps uses the native Animated library, but what I did was to make react-native-maps work with react-native-reanimated.&lt;/p&gt;

&lt;p&gt;Firstly, with some help from other devs, I had to create a useAnimatedRegion hook that did the actual animation using Reanimated's withTiming:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, {useCallback} from 'react';
import {MapMarker, MapMarkerProps} from 'react-native-maps';
import Animated, {
  Easing,
  EasingFunction,
  EasingFunctionFactory,
  SharedValue,
  useAnimatedProps,
  useAnimatedReaction,
  useSharedValue,
  withTiming,
} from 'react-native-reanimated';

interface LatLng {
  latitude: number;
  longitude: number;
  longitudeDelta?: number;
  latitudeDelta?: number;
}

interface AnimateOptions extends LatLng {
  duration?: number;
  easing?: EasingFunction | EasingFunctionFactory;
  rotation?: number;
  callback?: () =&amp;gt; void;
}

type MarkerProps = Omit&amp;lt;MapMarkerProps, 'coordinate'&amp;gt; &amp;amp; {
  coordinate?: MapMarkerProps['coordinate'];
};

export const AnimatedMarker = Animated.createAnimatedComponent(
  MapMarker as React.ComponentClass&amp;lt;MarkerProps&amp;gt;,
);

export const useAnimatedRegion = (
  location: Partial&amp;lt;LatLng&amp;gt; = {},
  animatedPosition?: SharedValue, 
) =&amp;gt; {
  const latitude = useSharedValue(location.latitude);
  const longitude = useSharedValue(location.longitude);
  const latitudeDelta = useSharedValue(location.latitudeDelta);
  const longitudeDelta = useSharedValue(location.longitudeDelta);
  const rotation = useSharedValue(undefined);

  const animatedProps = useAnimatedProps(() =&amp;gt; ({
    coordinate: {
      latitude: latitude.value ?? 0,
      longitude: longitude.value ?? 0,
      latitudeDelta: latitudeDelta.value ?? 0,
      longitudeDelta: longitudeDelta.value ?? 0,
      rotation: undefined,
    },
  }));

  useAnimatedReaction(
    () =&amp;gt; {
      return {
        latitude: latitude.value ?? 0,
        longitude: longitude.value ?? 0,
      };
    },
    (result, previous) =&amp;gt; {
      if (animatedPosition) {
        animatedPosition.value = result;
      }
    },
    [],
  );

  const animate = useCallback(
    (options: AnimateOptions) =&amp;gt; {
      const {duration = 500, easing = Easing.linear} = options;

      const animateValue = (
        value: SharedValue&amp;lt;number | undefined&amp;gt;,
        toValue?: number,
        callback?: () =&amp;gt; void,
      ) =&amp;gt; {
        if (!toValue) {
          return;
        }

        value.value = withTiming(
          toValue,
          {
            duration,
            easing,
          },
          callback,
        );
      };

      animateValue(latitude, options.latitude);
      animateValue(longitude, options.longitude, options.callback);
      animateValue(latitudeDelta, options?.latitudeDelta);
      animateValue(longitudeDelta, options?.longitudeDelta);
      //@ts-ignore
      animateValue(rotation, options?.rotation);
    },
    [latitude, longitude, latitudeDelta, longitudeDelta, rotation],
  );

  return {
    props: animatedProps,
    animate,
  };
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next I had to create the actual marker component that took a ref and used the useImperativeHandle hook from react to call the animate function on my png image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { forwardRef, useImperativeHandle, useRef } from "react";
import { SharedValue } from "react-native-reanimated";
import { AnimatedMarker, useAnimatedRegion } from "./useAnimatedMarker";
import { LatLng } from "react-native-maps";
import { LATITUDE_DELTA, LONGITUDE_DELTA } from "@env";
import { Image } from "react-native";

const carmaps = require("../../../assets/images/carmaps.png");

export interface MovingCarMarkerProps {
  defaultLocation: {
    latitude: number;
    longitude: number;
    heading: number;
  }; 
  heading?: number;
  animatedPosition?: SharedValue;
}

export interface MovingCarMarker {
  animateCarToPosition: (
    newCoords: LatLng,
    speed?: number,
    callback?: () =&amp;gt; void
  ) =&amp;gt; void;
}

export const MovingCarMarker = forwardRef(
  (props: MovingCarMarkerProps, ref) =&amp;gt; {
    const defaultCarRef = useRef({
      latitude: props?.defaultLocation?.latitude,
      longitude: props?.defaultLocation?.longitude,
      latitudeDelta: LATITUDE_DELTA,
      longitudeDelta: LONGITUDE_DELTA,
    });

    const animatedRegion = useAnimatedRegion(
      {
        latitude: parseFloat(
          defaultCarRef?.current?.latitude
            ? defaultCarRef?.current?.latitude?.toString()
            : "0"
        ),
        longitude: parseFloat(
          defaultCarRef?.current?.longitude
            ? defaultCarRef?.current?.longitude?.toString()
            : "0"
        ),
      },
      props?.animatedPosition
    );

    useImperativeHandle(ref, () =&amp;gt; ({
      animateCarToPosition: (
        newCoords: LatLng,
        speed?: number, 
        callback?: () =&amp;gt; void
      ) =&amp;gt; {
        animatedRegion.animate({
          latitude: newCoords?.latitude,
          longitude: newCoords?.longitude,
          duration: speed || 500,
          callback,
        });
      },
    }));

    return (
      &amp;lt;AnimatedMarker
        zIndex={20}
        anchor={{ x: 0.5, y: 0.5 }}
        rotation={props?.defaultLocation?.heading}
        animatedProps={animatedRegion.props}
      &amp;gt;
        &amp;lt;Image
          source={carmaps}
          style={{
            width: 40,
            height: 40
          }}
          resizeMode="contain"
        /&amp;gt;
      &amp;lt;/AnimatedMarker&amp;gt;
    );
  }
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once I had these two set up, all I had to do was to use my MovingCarMarker component within the styled MapView from react-native-maps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// in my custom hook
const carMarkerRef = useRef&amp;lt;MovingCarMarker | null&amp;gt;(null);

const handleUserLocationChange = ({
  nativeEvent: {coordinate},
}: UserLocationChangeEvent) =&amp;gt; {
  const newUserLocation = {
    coords: {
      latitude: coordinate?.latitude as number,
      longitude: coordinate?.longitude as number,
      heading: coordinate?.heading ?? 0,
    },
  };

  setUserLocation(newUserLocation);

  carMarkerRef?.current?.animateCarToPosition({
    latitude: newUserLocation?.coords?.latitude,
    longitude: newUserLocation?.coords?.longitude,
  });
};
// end of custom hook

&amp;lt;StyledMapView
  ref={models.mapRef}
  showsCompass={false}
  showsUserLocation={true}
  onUserLocationChange={operations.handleUserLocationChange}
  showsMyLocationButton={false}
  provider={PROVIDER_GOOGLE}
  customMapStyle={mapStyle}
  onRegionChangeComplete={operations.onregionChangeComplete}&amp;gt;
  {renderMapMarkers()}
  &amp;lt;MovingCarMarker
    ref={models?.carMarkerRef}
    defaultLocation={models?.defaultLocation}
  /&amp;gt;
  {operations?.returnPolyLine()}
&amp;lt;/StyledMapView&amp;gt;;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that in the handleUserLocationChange function, I not only use the ref to animate to a new position, I also update the models?.defaultLocation state been passed to the MovingCarMarker as defaultLocation with the new coordinates.&lt;/p&gt;

&lt;p&gt;With this set-up your custom marker would animate very smoothly between coordinates in your react-native app. Please let me know if this helps you in any way. Questions and contributions are also very welcome. &lt;/p&gt;

&lt;p&gt;Even with this solution, there's still a lot of room for improvement, so feel free to customize the implementation as you deem fit. &lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>mobile</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
