Flutter:从对象编辑新对象不正确地更改旧对象
Flutter: edit new object from object incorrectly changing old object
我正在尝试在我的生产力跟踪应用程序中包含一个编辑对象功能。我正在使用 Flutter、Firestore 和 Provider。我正在尝试允许用户在模态底部 sheet 中更新具有不同属性的任务(例如)。更新方面正在工作。如果用户按下更新按钮,它会正确更新 Firestore 并正确显示信息。我的问题是,当我取消模式时,发出取消更新的信号,它仍在更新原始任务对象。我什至尝试使用取消按钮来处理提供者,结果是一样的。我不确定为什么会这样。如果我重新加载应用程序,则会显示存储在 Firestore 中的正确值。这是正在发生的事情的视频:
这是我的任务模型:
class Task {
String taskID;
String taskName;
Project project;
Status status;
DateTime dueDate;
DateTime createDate;
Task({taskID, taskName, project, status, dueDate, createDate})
: taskID = taskID as String ?? '',
taskName = taskName as String ?? '',
project = project as Project ?? Project(),
status = status as Status ?? Status(),
dueDate = dueDate as DateTime ?? DateTime(0001, 01, 01, 0, 0, 0, 0, 555),
createDate = createDate as DateTime ?? DateTime.now();
这是我的提供商状态:
class TaskEditState extends ChangeNotifier {
Task newTask;
TaskEditState({newTask}) : newTask = newTask as Task ?? Task();
void updateTaskName(String taskName) {
newTask.taskName = taskName;
notifyListeners();
}
void updateTaskProject(Project project) {
newTask.project = project;
notifyListeners();
}
void updateTaskStatus(Status status) {
newTask.status = status;
notifyListeners();
}
void updateTaskDueDate(DateTime dueDate) {
if (newTask.dueDate.microsecond == 555) {
newTask.dueDate = dueDate;
} else {
final DateTime temp = newTask.dueDate;
newTask.dueDate = DateTime(
dueDate.year, dueDate.month, dueDate.day, temp.hour, temp.minute);
}
notifyListeners();
}
void updateTaskDueTime(TimeOfDay dueTime) {
if (newTask.dueDate.year == 0) {
newTask.dueDate = DateTime(0, 0, 0, dueTime.hour, dueTime.minute);
} else {
final DateTime temp = newTask.dueDate;
newTask.dueDate = DateTime(
temp.year, temp.month, temp.day, dueTime.hour, dueTime.minute);
}
notifyListeners();
}
void addTaskCreateDate(DateTime createDate) {
newTask.createDate = createDate;
}
这是我的编辑底部Sheet
TaskEditBottomSheet({
Key key,
this.isUpdate,
this.task,
}) : super(key: key);
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => TaskEditState(newTask: task),
builder: (context, child) {
final TaskEditState taskEditState = Provider.of<TaskEditState>(context);
final TaskService taskService = Provider.of<TaskService>(context);
print(taskEditState.newTask.project.projectName);
return Container(
margin: EdgeInsets.all(20),
child: Column(mainAxisSize: MainAxisSize.min, children: [
TextFormField(
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please Enter Project Name';
}
return null;
},
decoration: InputDecoration(
hintText: taskEditState.newTask.taskName.isEmpty
? 'Enter Task Name'
: taskEditState.newTask.taskName),
textAlign: TextAlign.center,
onChanged: (newText) {
taskEditState.updateTaskName(newText);
},
),
ProjectPicker(
saveProject: taskEditState.updateTaskProject,
child: ListTile(
leading: Icon(
Icons.circle,
color: Color(taskEditState.newTask.project.projectColor),
),
title: Text(
taskEditState.newTask.project.projectName.isEmpty
? 'Add Project'
: taskEditState.newTask.project.projectName,
style: Theme.of(context).textTheme.subtitle1),
trailing: Icon(Icons.arrow_drop_down_rounded,
color: Theme.of(context).unselectedWidgetColor),
),
),
StatusPicker(saveStatus: taskEditState.updateTaskStatus),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text('Due: ', style: Theme.of(context).textTheme.subtitle1),
OutlinedButton.icon(
onPressed: () => DateAndTimePickers().selectDate(
context: context,
initialDate: taskEditState.newTask.dueDate.year == 1
? DateTime.now()
: taskEditState.newTask.dueDate,
saveDate: taskEditState.updateTaskDueDate),
icon: Icon(Icons.today_rounded),
label: Text(taskEditState.newTask.dueDate.year == 1
? 'Add Due Date'
: DateTimeFunctions().dateTimeToTextDate(
date: taskEditState.newTask.dueDate)),
),
OutlinedButton.icon(
onPressed: () => DateAndTimePickers().selectTime(
context: context,
initialTime:
taskEditState.newTask.dueDate.microsecond == 555
? TimeOfDay.now()
: TimeOfDay.fromDateTime(
taskEditState.newTask.dueDate),
saveTime: taskEditState.updateTaskDueTime),
icon: Icon(Icons.alarm_rounded),
label: Text(taskEditState.newTask.dueDate.microsecond != 555
? DateTimeFunctions().dateTimeToTextTime(
date: taskEditState.newTask.dueDate,
context: context)
: 'Add Due Time'),
),
],
),
Container(
padding: EdgeInsets.symmetric(vertical: 20),
child:
ElevatedButton.icon(
icon: Icon(Icons.check_circle_outline_rounded),
label: Text(isUpdate ? 'Update' : 'Add'),
onPressed: () {
if (_formKey.currentState.validate()) {
isUpdate
? taskService.updateTask(
taskID: task.taskID,
updateData: taskEditState.newTask.toFirestore())
: taskService.addTask(
addData: taskEditState.newTask.toFirestore());
Navigator.pop(context);
}
},
),
)
]));
},
);
}
}
最后,这是调用底部的函数 sheet:
class EditBottomSheet {
Future<dynamic> buildEditBottomSheet(
{BuildContext context, Widget bottomSheet}) {
return showModalBottomSheet(
context: context,
enableDrag: true,
// isDismissible: false,
isScrollControlled:
true, // Allows the modal to me dynamic and keeps the menu above the keyboard
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25), topRight: Radius.circular(25))),
builder: (BuildContext context) {
return bottomSheet;
});
}
}
非常感谢任何帮助,谢谢!
我发现了我的问题。我不确定这是否是 Dart 和我使用过的其他东西之间的语言差异。在 Provider State 字段中,我将新任务设置为等于旧任务:
TaskEditState({newTask}) : newTask = newTask as Task ?? Task();
我了解到这是将新任务设置为等于旧任务的引用。因此,当我更改有关新任务的任何内容时,它也会更新旧任务。我猜这是因为它们实际上是同一个对象,而新任务是旧任务的副本。因此,我为所有复制原始任务和 return 副本的模型创建了一个模型函数。这完全解决了我的问题。这是更新后的提供商状态文件:
TaskEditState({this.oldTask}) {
if (oldTask != null) {
newTask = oldTask.copyTask();
} else {
newTask = Task();
}
}
这是我的复制功能:
Task copyTask() {
return Task(
id: id ?? '',
taskName: taskName ?? '',
project: project ?? Project(),
status: status ?? Status(),
dueDate: dueDate ?? DateTime(0001, 01, 01, 0, 0, 0, 0, 555),
createDate: createDate ?? DateTime.now());
}
我正在尝试在我的生产力跟踪应用程序中包含一个编辑对象功能。我正在使用 Flutter、Firestore 和 Provider。我正在尝试允许用户在模态底部 sheet 中更新具有不同属性的任务(例如)。更新方面正在工作。如果用户按下更新按钮,它会正确更新 Firestore 并正确显示信息。我的问题是,当我取消模式时,发出取消更新的信号,它仍在更新原始任务对象。我什至尝试使用取消按钮来处理提供者,结果是一样的。我不确定为什么会这样。如果我重新加载应用程序,则会显示存储在 Firestore 中的正确值。这是正在发生的事情的视频:
这是我的任务模型:
class Task {
String taskID;
String taskName;
Project project;
Status status;
DateTime dueDate;
DateTime createDate;
Task({taskID, taskName, project, status, dueDate, createDate})
: taskID = taskID as String ?? '',
taskName = taskName as String ?? '',
project = project as Project ?? Project(),
status = status as Status ?? Status(),
dueDate = dueDate as DateTime ?? DateTime(0001, 01, 01, 0, 0, 0, 0, 555),
createDate = createDate as DateTime ?? DateTime.now();
这是我的提供商状态:
class TaskEditState extends ChangeNotifier {
Task newTask;
TaskEditState({newTask}) : newTask = newTask as Task ?? Task();
void updateTaskName(String taskName) {
newTask.taskName = taskName;
notifyListeners();
}
void updateTaskProject(Project project) {
newTask.project = project;
notifyListeners();
}
void updateTaskStatus(Status status) {
newTask.status = status;
notifyListeners();
}
void updateTaskDueDate(DateTime dueDate) {
if (newTask.dueDate.microsecond == 555) {
newTask.dueDate = dueDate;
} else {
final DateTime temp = newTask.dueDate;
newTask.dueDate = DateTime(
dueDate.year, dueDate.month, dueDate.day, temp.hour, temp.minute);
}
notifyListeners();
}
void updateTaskDueTime(TimeOfDay dueTime) {
if (newTask.dueDate.year == 0) {
newTask.dueDate = DateTime(0, 0, 0, dueTime.hour, dueTime.minute);
} else {
final DateTime temp = newTask.dueDate;
newTask.dueDate = DateTime(
temp.year, temp.month, temp.day, dueTime.hour, dueTime.minute);
}
notifyListeners();
}
void addTaskCreateDate(DateTime createDate) {
newTask.createDate = createDate;
}
这是我的编辑底部Sheet
TaskEditBottomSheet({
Key key,
this.isUpdate,
this.task,
}) : super(key: key);
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => TaskEditState(newTask: task),
builder: (context, child) {
final TaskEditState taskEditState = Provider.of<TaskEditState>(context);
final TaskService taskService = Provider.of<TaskService>(context);
print(taskEditState.newTask.project.projectName);
return Container(
margin: EdgeInsets.all(20),
child: Column(mainAxisSize: MainAxisSize.min, children: [
TextFormField(
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please Enter Project Name';
}
return null;
},
decoration: InputDecoration(
hintText: taskEditState.newTask.taskName.isEmpty
? 'Enter Task Name'
: taskEditState.newTask.taskName),
textAlign: TextAlign.center,
onChanged: (newText) {
taskEditState.updateTaskName(newText);
},
),
ProjectPicker(
saveProject: taskEditState.updateTaskProject,
child: ListTile(
leading: Icon(
Icons.circle,
color: Color(taskEditState.newTask.project.projectColor),
),
title: Text(
taskEditState.newTask.project.projectName.isEmpty
? 'Add Project'
: taskEditState.newTask.project.projectName,
style: Theme.of(context).textTheme.subtitle1),
trailing: Icon(Icons.arrow_drop_down_rounded,
color: Theme.of(context).unselectedWidgetColor),
),
),
StatusPicker(saveStatus: taskEditState.updateTaskStatus),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text('Due: ', style: Theme.of(context).textTheme.subtitle1),
OutlinedButton.icon(
onPressed: () => DateAndTimePickers().selectDate(
context: context,
initialDate: taskEditState.newTask.dueDate.year == 1
? DateTime.now()
: taskEditState.newTask.dueDate,
saveDate: taskEditState.updateTaskDueDate),
icon: Icon(Icons.today_rounded),
label: Text(taskEditState.newTask.dueDate.year == 1
? 'Add Due Date'
: DateTimeFunctions().dateTimeToTextDate(
date: taskEditState.newTask.dueDate)),
),
OutlinedButton.icon(
onPressed: () => DateAndTimePickers().selectTime(
context: context,
initialTime:
taskEditState.newTask.dueDate.microsecond == 555
? TimeOfDay.now()
: TimeOfDay.fromDateTime(
taskEditState.newTask.dueDate),
saveTime: taskEditState.updateTaskDueTime),
icon: Icon(Icons.alarm_rounded),
label: Text(taskEditState.newTask.dueDate.microsecond != 555
? DateTimeFunctions().dateTimeToTextTime(
date: taskEditState.newTask.dueDate,
context: context)
: 'Add Due Time'),
),
],
),
Container(
padding: EdgeInsets.symmetric(vertical: 20),
child:
ElevatedButton.icon(
icon: Icon(Icons.check_circle_outline_rounded),
label: Text(isUpdate ? 'Update' : 'Add'),
onPressed: () {
if (_formKey.currentState.validate()) {
isUpdate
? taskService.updateTask(
taskID: task.taskID,
updateData: taskEditState.newTask.toFirestore())
: taskService.addTask(
addData: taskEditState.newTask.toFirestore());
Navigator.pop(context);
}
},
),
)
]));
},
);
}
}
最后,这是调用底部的函数 sheet:
class EditBottomSheet {
Future<dynamic> buildEditBottomSheet(
{BuildContext context, Widget bottomSheet}) {
return showModalBottomSheet(
context: context,
enableDrag: true,
// isDismissible: false,
isScrollControlled:
true, // Allows the modal to me dynamic and keeps the menu above the keyboard
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25), topRight: Radius.circular(25))),
builder: (BuildContext context) {
return bottomSheet;
});
}
}
非常感谢任何帮助,谢谢!
我发现了我的问题。我不确定这是否是 Dart 和我使用过的其他东西之间的语言差异。在 Provider State 字段中,我将新任务设置为等于旧任务:
TaskEditState({newTask}) : newTask = newTask as Task ?? Task();
我了解到这是将新任务设置为等于旧任务的引用。因此,当我更改有关新任务的任何内容时,它也会更新旧任务。我猜这是因为它们实际上是同一个对象,而新任务是旧任务的副本。因此,我为所有复制原始任务和 return 副本的模型创建了一个模型函数。这完全解决了我的问题。这是更新后的提供商状态文件:
TaskEditState({this.oldTask}) {
if (oldTask != null) {
newTask = oldTask.copyTask();
} else {
newTask = Task();
}
}
这是我的复制功能:
Task copyTask() {
return Task(
id: id ?? '',
taskName: taskName ?? '',
project: project ?? Project(),
status: status ?? Status(),
dueDate: dueDate ?? DateTime(0001, 01, 01, 0, 0, 0, 0, 555),
createDate: createDate ?? DateTime.now());
}