Skip to content

Handling Data in Flutter

React and Flutter solve the same fundamental data problems — fetch something async, hold it in state, propagate it through the tree — but the APIs look different at every layer. This module maps the React mental model you already have onto Flutter’s equivalents so you can skip the confusion and get productive fast.

If you know what React tool you reach for, here is the Flutter equivalent:

React conceptFlutter equivalentNotes
PromiseFuture<T>Same single-value async wrapper. async/await works identically.
async/awaitasync/awaitDart syntax is nearly identical to JS.
fetch / axioshttp package (http.get)Add http to pubspec.yaml. Returns a Future<Response>.
useEffect + setStateFutureBuilder<T>Declarative widget that rebuilds on Future state changes.
React.createContext + useContextProvider / InheritedWidgetprovider package is the idiomatic choice.
react-query / SWRriverpod (AsyncNotifier)Caching, background refresh, error states — same ideas.
JSON.parsejsonDecode + model .fromJsonDart is typed, so you map the decoded map to a class manually (or with json_serializable).
Promise.allFuture.waitRuns multiple Futures concurrently, resolves when all complete.
try/catch in asynctry/catch in asyncIdentical pattern. Future also has .catchError() for chain-style handling.
  • Futures and async/await — the PromiseFuture mapping in depth, .then(), .catchError(), and try/catch patterns.
  • HTTP and JSON — using the http package to fetch real data and parsing typed Dart models from JSON.
  • FutureBuilder — Flutter’s declarative way to render async state (loading / error / data) without useEffect.
  • Provider — sharing data across the widget tree, the Flutter equivalent of React Context.

The snippet below simulates an async data load using Future.delayed — no network needed. It mirrors the useEffect(() => fetch(...), []) pattern you write in React, but expressed as a FutureBuilder widget.

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: Center(child: AsyncGreeting()),
      ),
    );
  }
}

// Simulates an async data fetch — like useEffect + fetch in React.
Future<String> fetchGreeting() {
  return Future.delayed(
    const Duration(seconds: 2),
    () => 'Hello from the Flutter data layer!',
  );
}

class AsyncGreeting extends StatelessWidget {
  const AsyncGreeting({super.key});

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<String>(
      future: fetchGreeting(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              CircularProgressIndicator(),
              SizedBox(height: 16),
              Text('Loading...', style: TextStyle(color: Colors.grey)),
            ],
          );
        }
        if (snapshot.hasError) {
          return Text('Error: ${snapshot.error}',
              style: const TextStyle(color: Colors.red));
        }
        return Text(
          snapshot.data ?? '',
          style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
        );
      },
    );
  }
}
What is the Flutter equivalent of a JavaScript Promise?
Which Flutter widget declaratively handles the loading / error / data states of an async operation?