Skip to main content

Overview

The cryptocurrency list view is the main interface for browsing available cryptocurrencies. It displays a scrollable list of crypto cards with real-time data and supports scroll-to-top functionality for improved navigation.

Implementation

The list view is implemented in HomeScreen.tsx and uses the CryptoList component to render individual cryptocurrency cards.

HomeScreen Component

The main screen component manages the filtered cryptocurrency data and scroll behavior:
HomeScreen.tsx
const HomeScreen = () => {
  const { data, loading, error } = useCryptoData();
  const { filter } = useFilter();
  const [scrollY, setScrollY] = useState(0);
  const scrollViewRef = useRef<ScrollView>(null);

  // Filter cryptocurrencies based on context filter
  const filtered = data.filter((crypto) => {
    const nameMatch = crypto.name.toLowerCase().includes(filter.text.toLowerCase());
    const symbolMatch = crypto.symbol.toLowerCase().includes(filter.text.toLowerCase());
    const minOk = filter.minPrice === null || Number(crypto.price_usd) >= filter.minPrice;
    const maxOk = filter.maxPrice === null || Number(crypto.price_usd) <= filter.maxPrice;
    
    return (nameMatch || symbolMatch) && minOk && maxOk;
  });

  return (
    <ScrollView
      onScroll={handleScroll}
      scrollEventThrottle={16}
      ref={scrollViewRef}
    >
      {filtered.map((crypto) => (
        <CryptoCard key={crypto.id} crypto={crypto} />
      ))}
    </ScrollView>
  );
};
The filtering logic combines both text search (name/symbol) and price range filters to provide a comprehensive filtering experience.

CryptoList Component

An alternative implementation using FlatList for better performance with large datasets:
CryptoList.tsx
const CryptoList = () => {
  const { data, loading, error } = useCryptoData();

  if (loading) {
    return (
      <View style={styles.center}>
        <ActivityIndicator size="large" color="#00e676" />
        <Text>Cargando criptomonedas...</Text>
      </View>
    );
  }

  if (error) {
    return (
      <View style={styles.center}>
        <Text style={styles.errorText}>Error al cargar las criptomonedas</Text>
      </View>
    );
  }

  return (
    <FlatList
      data={data}
      keyExtractor={(item) => item.id.toString()}
      renderItem={({ item }) => <CryptoCard crypto={item} />}
    />
  );
};

CryptoCard Component

Each cryptocurrency is displayed using the CryptoCard component, which shows:
  • Name and Symbol: Cryptocurrency full name and ticker symbol
  • Rank: Market ranking position
  • Current Price: USD value formatted as currency
  • 24h Change: Percentage change with color coding (green for positive, red for negative)
CryptoCard.tsx
const CryptoCard = ({ crypto }: Props) => {
  const router = useRouter();
  const price = parseFloat(crypto.price_usd || '0');
  const change = parseFloat(crypto.percent_change_24h || '0');
  const isPositive = change >= 0;

  return (
    <Pressable onPress={() => router.push(`/crypto/${crypto.id}`)}>
      <TouchableOpacity style={styles.card}>
        <View style={styles.topRow}>
          <View>
            <Text style={styles.name}>{crypto.name}</Text>
            <Text style={styles.symbol}>({crypto.symbol})</Text>
          </View>
          <Text style={styles.rank}>#{crypto.rank}</Text>
        </View>

        <View style={styles.bottomRow}>
          <Text style={styles.price}>{formatToUSD(price)}</Text>
          <Text style={[styles.change, isPositive ? styles.positive : styles.negative]}>
            {isPositive ? '+' : ''}{change.toFixed(2)}% (24h)
          </Text>
        </View>
      </TouchableOpacity>
    </Pressable>
  );
};

Card Styling

The crypto cards feature a dark blue background (#1c1c7e) with shadow effects for depth:
const styles = StyleSheet.create({
  card: {
    backgroundColor: '#1c1c7e',
    borderRadius: 12,
    padding: 16,
    marginVertical: 10,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 6 },
    shadowOpacity: 0.25,
    shadowRadius: 10,
    elevation: 5,
  },
  // ... other styles
});

Scroll-to-Top Functionality

The HomeScreen implements a floating button that appears when users scroll down more than 200 pixels:
const handleScroll = (event: any) => {
  setScrollY(event.nativeEvent.contentOffset.y);
};

const scrollToTop = () => {
  if (scrollViewRef.current) {
    scrollViewRef.current.scrollTo({ y: 0, animated: true });
  }
};

// Render scroll-to-top button
{scrollY > 200 && (
  <TouchableOpacity style={styles.scrollToTopButton} onPress={scrollToTop}>
    <Text style={styles.buttonText}></Text>
  </TouchableOpacity>
)}
The scroll button is positioned absolutely at the bottom-right corner with a black background and uses scrollEventThrottle={16} for smooth scroll tracking at 60fps.

Button Styling

const styles = StyleSheet.create({
  scrollToTopButton: {
    position: 'absolute',
    bottom: 30,
    right: 30,
    backgroundColor: '#000',
    padding: 10,
    borderRadius: 30,
    elevation: 5,
  },
  buttonText: {
    color: 'white',
    fontSize: 18,
    fontWeight: 'bold',
  },
});

Loading and Error States

The list view handles three states:
{loading && (
  <ActivityIndicator 
    size="large" 
    color="#0000ff" 
    style={styles.loader} 
  />
)}

Key Features

  • Real-time Data: Uses useCryptoData hook to fetch live cryptocurrency data
  • Optimized Rendering: Choose between ScrollView (HomeScreen) or FlatList (CryptoList) based on performance needs
  • Interactive Cards: Each card is tappable and navigates to the detail view
  • Visual Feedback: Color-coded price changes (green/red) provide instant visual cues
  • Smooth Scrolling: Throttled scroll events ensure smooth performance
  • Accessibility: Large touch targets and clear visual hierarchy

Build docs developers (and LLMs) love