riverpod icon indicating copy to clipboard operation
riverpod copied to clipboard

Alternatives to AVOID initializing providers in a widget

Open MiniSuperDev opened this issue 2 months ago • 0 comments

Respecting this don't in AVOID initializing providers in a widget.

class WidgetState extends State<MyWidget> {
  @override
  void initState() {
    super.initState();
    // Bad: the provider should initialize itself
    ref.read(provider).init();
  }
}

I have seen these 2 other ways to initialize a provider apart from Eager initialization.

I would like clarification if these 2 cases are okay or could lead to possible race conditions and unexpected behavior.

I've used before and seems to work fine, but I would like you to clarify this please.

Thanks.

Case 1: Initializing with addPostFrameCallback in initState

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'main.g.dart';

@Riverpod(keepAlive: true)
class TextNotifier extends _$TextNotifier {
  @override
  String build() => 'build';
  void init() async {
    state = 'loading';
    await Future.delayed(Duration(seconds: 2));
    state = 'initiated';
  }
}

void main() {
  runApp(
    ProviderScope(
      child: MaterialApp(home: HomePage()),
    ),
  );
}

class HomePage extends ConsumerStatefulWidget {
  @override
  ConsumerState<HomePage> createState() => _HomePageState();
}

class _HomePageState extends ConsumerState<HomePage> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      ref.read(textNotifierProvider.notifier).init();
    });
  }

  @override
  Widget build(BuildContext context) {
    final text = ref.watch(textNotifierProvider);
    return Center(child: Text(text));
  }
}


Case 2: Initializing in the main and UncontrolledProviderScope

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'main.g.dart';

@Riverpod(keepAlive: true)
class TextNotifier extends _$TextNotifier {
  @override
  String build() => 'build';
  void init() async {
    state = 'loading';
    await Future.delayed(Duration(seconds: 2));
    state = 'initiated';
  }
}

void main() {
  final container = ProviderContainer();
  container.read(textNotifierProvider.notifier).init();
  runApp(
    UncontrolledProviderScope(
      container: container,
      child: MaterialApp(home: HomePage()),
    ),
  );
}

class HomePage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final text = ref.watch(textNotifierProvider);
    return Center(child: Text(text));
  }
}

MiniSuperDev avatar May 01 '24 00:05 MiniSuperDev