flutterriverpodfreezedflutter-freezed

Freezed copyWith method not avaliable for List<T> model in Union/Sealed? (using Flutter with Freezed package)


How can I get my code (Flutter using Freezed) to obtain use of the "copyWith" freezed feature for updating state here?

Freezed Class:

import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'todo_list.freezed.dart';
part 'todo_list.g.dart';

@freezed 
class TodoList with _$TodoList {
  const TodoList._();
  factory TodoList({ required List<String> titles }) = _TodoList;
  factory TodoList.loading() = Loading;
  factory TodoList.error([String? message]) = ErrorDetails;

  factory TodoList.fromJson(Map<String, dynamic> json) => _$TodoListFromJson(json);

}

State Notifier

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:gc_todo/presentation/state/todo_list.dart';
import 'dart:developer' as developer;

final todoListProvider = StateNotifierProvider((ref) => TodoListNotifier());

class TodoListNotifier extends StateNotifier<TodoList> {
  TodoListNotifier() : super( TodoList(titles: ["first", "second"]) );

  void addTodoList(String newTitle) {
    developer.log("addTodoList - $state");
    if (state is List<String>) (List<String> stateToUse) {
      stateToUse.copyWith();  // STILL DOES NOT RECOGNISE "copyWith"
    };
  }

}

enter image description here


Solution

  • Freezed uses wrapper types around each variant of your union type, in this case TodoList. The "list" variant of that type is not List<String> as you seem to be assuming.

    Also, copyWith only works with properties defined in all union variants, which in your case is none.

    You should use when to "pattern match" over all variants of that type, or maybeWhen to match a sub-set only.

    Here's something that should work in your case:

    class TodoListNotifier extends StateNotifier<TodoList> {
      TodoListNotifier() : super( TodoList(titles: ["first", "second"]) );
    
      void addTodoList(String newTitle) {
        developer.log("addTodoList - $state");
        state.maybeWhen(
            (items) => setState(TodoList(titles: [...items, newTitle]),
            orElse: () { /* TODO */ }
        );
      }
    
    }