LOADING BASE0%
Portfolio Logo
Back to posts
ExpoReduxReact NativeMobile

Building Real-Time Social Platforms with Expo and Redux

3 min read

Building Real-Time Social Delivery in Expo

When we created Zoomies under the XRide Labs umbrella, the mission was simple: build a social platform for motorcyclists that felt instantly responsive. Riders needed to see each other on a live map, chat in real-time, and drop pins that would propagate across the network in milliseconds.

To achieve this, we combined the cross-platform power of Expo with the predictable state management of Redux Toolkit.

1. Expo Router: The Next.js of Mobile

If you've used React Native before 2024, you've suffered the wrath of React Navigation configs. Expo Router completely flipped the script by bringing file-based routing to mobile.

Instead of registering screens in a massive navigator file:

// app/(tabs)/map.tsx
import { useLocalSearchParams } from "expo-router";
 
export default function MapScreen() {
  const { eventId } = useLocalSearchParams();
 
  return (
    <View style={styles.container}>
      <LiveRiderMap eventId={eventId} />
    </View>
  );
}

2. Redux as a Socket Consumer

Sockets constantly push thousands of events. Rather than passing state down the component tree or relying exclusively on Context (which would trigger full-app renders on every socket push), we bound socket.io-client straight into Redux slices.

// store/ridersSlice.ts
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
 
interface RiderState {
  locations: Record<string, { lat: number; lng: number }>;
}
 
const initialState: RiderState = { locations: {} };
 
const ridersSlice = createSlice({
  name: "riders",
  initialState,
  reducers: {
    updateRiderLocation: (
      state,
      action: PayloadAction<{ id: string; lat: number; lng: number }>,
    ) => {
      // Redux Toolkit uses Immer, allowing us to "mutate" state directly
      state.locations[action.payload.id] = {
        lat: action.payload.lat,
        lng: action.payload.lng,
      };
    },
  },
});

3. Batched Updates

If you have 100 riders emitting location updates every 3 seconds, that's 33 Redux actions dispatched per second. To prevent the UI from shuddering, we implemented a custom batched middleware that collects socket messages and dispatches them in a single chunk every 500ms.

let locationQueue = [];
 
socket.on("rider_move", (data) => {
  locationQueue.push(data);
});
 
setInterval(() => {
  if (locationQueue.length > 0) {
    store.dispatch(batchUpdateRiders(locationQueue));
    locationQueue = [];
  }
}, 500);

Conclusion

Building Zoomies proved that Expo is no longer just for "toys". With sensible architectural patterns, Redux state batching, and native rendering through Expo Router, you can build heavy, real-time spatial applications without ever touching Xcode or Android Studio.