首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ChangeNotifier到StateNotifier的实现

ChangeNotifier到StateNotifier的实现
EN

Stack Overflow用户
提问于 2022-04-08 13:51:33
回答 1查看 128关注 0票数 0

我已经将我的ChangeNotifier代码重写为StateNotifier,但问题是当您按下“喜欢”或“不喜欢”学生行中的“学生”按钮时,它不会重新生成。我希望ref.watch()侦听likedStudentsNotifier的状态,并在发生更改时重新构建StudentRow小部件。但事实并非如此。为什么会发生这种事?要解决StudentRow类中的问题,我可以在setState而不是ConsumerWidget中使用ConsumerStatefulWidget,但我想知道它是如何工作的?

ChangeNotifier:

代码语言:javascript
复制
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(const ProviderScope(child: Schoolapp()));
}

class Schoolapp extends StatelessWidget {
  const Schoolapp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'School App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(title: 'School App Main Page'),
    );
  }
}

class HomePage extends ConsumerWidget {
  const HomePage({Key? key, required this.title}) : super(key: key);

  final String title;


  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            TextButton(
              child: Text('${ref.watch(studentsProvider).studentsList.length} Students'),
              onPressed: () {
                _runStudentsPage(context);
              },
            ),
          ],
        ),
      ),
    );
  }

  void _runStudentsPage(BuildContext context) {
    Navigator.of(context).push(MaterialPageRoute(
      builder: (context) {
        return const StudentsPage();
      },
    ));
  }
}

class StudentsPage extends ConsumerWidget {
  const StudentsPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(title: const Text('Students')),
      body: Column(
        children: [
          PhysicalModel(
            color: Colors.white,
            elevation: 10,
            child: Center(
              child: Padding(
                padding: const EdgeInsets.symmetric(vertical: 32.0, horizontal: 32.0),
                child: Text(
                    '${ref.watch(studentsProvider).studentsList.length} Students'
                ),
              ),
            ),
          ),
          Expanded(
            child: ListView.separated(
              itemBuilder: (context, index) => StudentRow(
                ref.watch(studentsProvider).studentsList[index],
              ),
              separatorBuilder: (context, index) => const Divider(),
              itemCount: ref.watch(studentsProvider).studentsList.length,
            ),
          ),
        ],
      ),
    );
  }

}

class StudentRow extends ConsumerWidget {
  final StudentModel student;
  const StudentRow(this.student, {
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    bool isLiked = ref.watch(studentsProvider).isLiked(student);
    return ListTile(
      title: Text(student.name + ' ' + student.surName),
      leading: IntrinsicWidth(child: Center(child: Text(student.gender == 'Female' ? '‍' : '‍'))),
      trailing: IconButton(
        onPressed: () {
          ref.read(studentsProvider).like(student, !isLiked);
        },
        icon: Icon(isLiked ?  Icons.favorite : Icons.favorite_border),
      ),
    );
  }
}

class StudentsRepository extends ChangeNotifier {

  final studentsList = [
    StudentModel('Aziz', 'Sancar', 18, 'Male'),
    StudentModel('Iggy', 'Azalea', 20, 'Female'),
    StudentModel('Madonna', 'Rrww', 22, 'Female'),
  ];

  final Set<StudentModel> likedStudents = {};

  void like(StudentModel student, bool isLiked) {
    if (isLiked == true) {
      likedStudents.add(student);
    } else {
      likedStudents.remove(student);
    }
    notifyListeners();
  }

  bool isLiked(StudentModel student) {
    return likedStudents.contains(student);
  }
}

final studentsProvider = ChangeNotifierProvider((ref) {
  return StudentsRepository();
});


class StudentModel {
  String name;
  String surName;
  int age;
  String gender;

  StudentModel(this.name, this.surName, this.age, this.gender);
}

StateNotifier:

代码语言:javascript
复制
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(const ProviderScope(child: const Schoolapp()));
}

class Schoolapp extends StatelessWidget {
  const Schoolapp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'School App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(title: 'School App Main Page'),
    );
  }
}

class HomePage extends ConsumerWidget {
  const HomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            TextButton(
              child: Text(
                  '${ref.watch(studentsProvider.notifier).state.length} Students'),
              onPressed: () {
                _runStudentsPage(context);
              },
            ),
          ],
        ),
      ),
    );
  }

  void _runStudentsPage(BuildContext context) {
    Navigator.of(context).push(MaterialPageRoute(
      builder: (context) {
        return StudentsPage();
      },
    ));
  }
}

class StudentsPage extends ConsumerWidget {
  const StudentsPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(title: const Text('Students Page')),
      body: Column(
        children: [
          PhysicalModel(
            color: Colors.white,
            elevation: 10,
            child: Center(
              child: Padding(
                padding: const EdgeInsets.symmetric(
                    vertical: 32.0, horizontal: 32.0),
                child: Text(
                    '${ref.watch(studentsProvider.notifier).state.length} Students'),
              ),
            ),
          ),
          Expanded(
            child: ListView.separated(
              itemBuilder: (context, index) => StudentRow(
                ref.watch(studentsProvider.notifier).state[index],
              ),
              separatorBuilder: (context, index) => const Divider(),
              itemCount: ref.watch(studentsProvider.notifier).state.length,
            ),
          ),
        ],
      ),
    );
  }
}

class StudentRow extends ConsumerWidget {
  final StudentModel student;

  const StudentRow(
    this.student, {
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    bool isStudentLiked =
        ref.watch(likedStudentsProvider.notifier).isLiked(student);

    return ListTile(
      title: Text(student.name + ' ' + student.surName),
      leading: IntrinsicWidth(
          child: Center(
              child: Text(student.gender == 'Female' ? '‍' : '‍'))),
      trailing: IconButton(
        onPressed: () {
          ref
              .read(likedStudentsProvider.notifier)
              .likeStudent(student, !isStudentLiked);
        },
        icon: Icon(isStudentLiked ? Icons.favorite : Icons.favorite_border),
      ),
    );
  }
}

class StudentsRepository extends StateNotifier<List<StudentModel>> {
  StudentsRepository() : super([]);

  addStudent(StudentModel studentToAdd) {
    return state = [...state, studentToAdd];
  }

  @override
  final state = [
    StudentModel('Aziz', 'Sancar', 18, 'Male'),
    StudentModel('Iggy', 'Azalea', 20, 'Female'),
    StudentModel('Madonna', 'Rrww', 22, 'Female'),
  ];
}

class likedStudentsNotifier extends StateNotifier<Set<StudentModel>> {
  likedStudentsNotifier() : super({});

  Set<StudentModel> state = {};

  void likeStudent(StudentModel studentToAdd, bool isLiked) {
    if (isLiked == true) {
      state = {...state, studentToAdd};
    } else {
      state = {
        for (final student in state)
          if (student != studentToAdd) student,
      };
    }
  }

  isLiked(StudentModel student) {
    return state.contains(student);
  }
}

class StudentModel {
  String name;
  String surName;
  int age;
  String gender;

  StudentModel(this.name, this.surName, this.age, this.gender);
}

final likedStudentsProvider =
    StateNotifierProvider<likedStudentsNotifier, Set<StudentModel>>((ref) {
  return likedStudentsNotifier();
});

final studentsProvider = StateNotifierProvider<StudentsRepository, List>((ref) {
  return StudentsRepository();
});
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-08 17:24:54

你的问题是以一种糟糕的方式阅读notifierref.watch(provider.notifier).stateref.watch(provider),左边是坏的。我已经将您的代码重写为更干净的代码,并且在如何处理StateNotifier中的状态方面具有更好的实践。你可以比较我的代码和你的代码,看看出了什么问题。

代码语言:javascript
复制
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(const ProviderScope(child: Schoolapp()));
}

class Schoolapp extends StatelessWidget {
  const Schoolapp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'School App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(title: 'School App Main Page'),
    );
  }
}

class HomePage extends ConsumerWidget {
  const HomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            TextButton(
              child: Text(
                '${ref.watch(studentsProvider).length} Students',
              ),
              onPressed: () {
                _runStudentsPage(context);
              },
            ),
          ],
        ),
      ),
    );
  }

  void _runStudentsPage(BuildContext context) {
    Navigator.of(context).push(MaterialPageRoute(
      builder: (context) {
        return const StudentsPage();
      },
    ));
  }
}

class StudentsPage extends ConsumerWidget {
  const StudentsPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(title: const Text('Students Page')),
      body: Column(
        children: [
          PhysicalModel(
            color: Colors.white,
            elevation: 10,
            child: Center(
              child: Padding(
                padding: const EdgeInsets.symmetric(
                    vertical: 32.0, horizontal: 32.0),
                child: Text('${ref.watch(studentsProvider).length} Students'),
              ),
            ),
          ),
          Expanded(
            child: ListView.separated(
              itemBuilder: (context, index) => StudentRow(
                ref.watch(studentsProvider)[index],
              ),
              separatorBuilder: (context, index) => const Divider(),
              itemCount: ref.read(studentsProvider).length,
            ),
          ),
        ],
      ),
    );
  }
}

class StudentRow extends ConsumerWidget {
  final StudentModel student;

  const StudentRow(
    this.student, {
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ListTile(
      title: Text(student.name + ' ' + student.surName),
      leading: IntrinsicWidth(
        child: Center(
          child: Text(student.gender == 'Female' ? '‍' : '‍'),
        ),
      ),
      trailing: IconButton(
        onPressed: () {
          ref.read(studentsProvider.notifier).like(student);
        },
        icon: Icon(student.isLiked ? Icons.favorite : Icons.favorite_border),
      ),
    );
  }
}

class StudentsRepository extends StateNotifier<List<StudentModel>> {
  StudentsRepository()
      : super([
          StudentModel('Aziz', 'Sancar', 18, 'Male', false),
          StudentModel('Iggy', 'Azalea', 20, 'Female', false),
          StudentModel('Madonna', 'Rrww', 22, 'Female', false),
        ]);

  void add(StudentModel student) {
    state = [...state, student];
  }

  void like(StudentModel student) {
    state = [
      for (var element in state)
        if (element == student)
          StudentModel(
            element.name,
            element.surName,
            element.age,
            element.gender,
            element.isLiked = !element.isLiked,
          )
        else
          element
    ];
  }

  void remove(StudentModel student) {
    state = state.where((e) => e != student).toList();
  }
}

class StudentModel {
  String name;
  String surName;
  int age;
  String gender;
  bool isLiked;

  StudentModel(this.name, this.surName, this.age, this.gender, this.isLiked);

  @override
  bool operator ==(covariant StudentModel model) {
    return model.name == name &&
        model.surName == surName &&
        model.age == age &&
        model.gender == gender &&
        model.isLiked == isLiked;
  }

  @override
  int get hashCode =>
      name.hashCode ^
      surName.hashCode ^
      age.hashCode ^
      gender.hashCode ^
      isLiked.hashCode;
}

final studentsProvider = StateNotifierProvider<StudentsRepository, List>((ref) {
  return StudentsRepository();
});
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71798250

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档