Comments 4
onPressed: controller.like
И что-то вроде ObxValue(builder, likesObserver)
В любом случае, за «сеттером» controller.like спрячется вся логика. Можно, конечно, спрятать ее за оператором инкремента, чтобы было красиво, но что-то не кажется, что игра стоит свеч.
P.S. И, может быть, не надо вставлять код картинками?
Зачем в представлении делать counter++ и дальше говорить о каком-то UDF?
Потому что под капотом декоратора находится переопределение оператора ++ (полная мимикрия под стандартный Rx<int>, а как же иначе - это же паттерн "декоратор"), и инкремент значения не изменится напрямую, а только лишь после взаимодействия с логикой модели, посмотрите код в гисте, там кстати полно юнит-тестов и есть пример для понимания работы.
Вкратце поток логики будет такой:
View скомандовала, что хочет инкремента
Сеттер (часть модели) провел операции над этой командой, приняв решение
Значение реактивного поля изменилось
View реактивно перерисовалась
Никак иначе чем через модель, изменение и команда на перерисовку не произойдет. Ровный такой UDF.
Ведь в реальности во вью будет какой-нибудь...
Ваши сниппеты не очень информативны, но давайте я попробую построить на них свои предположения.
Видимо речь идет о лайках. Пусть количество лайков за каждый клик зависит от "веса клиента", например, каждый клик админа будет добавлять по два лайка. Налицо логика, которую надо прятать от View. Строим вашим методом
/// Модель для счетчика лайков.
class LikesController extends GetxController {
/// Чисто обыгрыш логики.
static const _isAdmin = true;
/// Сама переменная, которая не может быть приватной, следовательно
/// доступна для нарушения инкапсуляции и логики.
var likeCounter = 0.obs;
/// Метод изменения переменной.
void like() {
if (_isAdmin) {
likeCounter.value = likeCounter() + 2;
} else {
likeCounter.value = likeCounter() + 1;
}
}
}
/// Где-то на View
ObxValue(
(data) => ElevatedButton(
onPressed: c.like,
child: Text('Std Likes: $data'),
),
c.likeCounter,
),
Ну вроде все норм, только есть нюанс. Переменная likeCounter
публична (а как иначе, если только не накладывать ограничения на размещение контроллера в пакедже View, ну или другие фокусы). Соответственно, никто не мешает постучаться в нее напрямую:
ObxValue(
(data) => ElevatedButton(
// Уппс, ай дид ит эген
onPressed: () => c.likeCounter.value = c.likeCounter.value + 1,
child: Text('Std Likes: $data'),
),
c.likeCounter,
),
и вся логика превратится в тыкву.
Давайте теперь применим GetRxDecorator
.
/// 4-в-1: Rx-переменная, геттер, сеттер + стрим на всякий случай.
/// Строгая инкапсуляция _значения_ переменной.
final likeCounterDeco = 0.obsDeco(setter: (oldValue, _, __) {
if (_isAdmin) {
return oldValue + 2;
} else {
return oldValue + 1;
}
});
А в клиенте будет как-то так
Obx(
() => ElevatedButton(
onPressed: c.likeCounterDeco,
child: Text('Decorator Likes: ${c.likeCounterDeco}'),
),
),
Ни при каких случайных условиях вам не удастся нарушить инкапсуляцию и UDF поток данных, ну только если ужасно сильно постараться.
P.S. И, может быть, не надо вставлять код картинками?
Да, зря я так. Надо будет поправить, согласен. Но с другой стороны это же просто сниппеты, а в gist и в pub.dev есть полный код, примеры и тесты.
Это старая история, да, не буду холиварить. Я ж говорю, статья для тех, кто использует GetX именно в плоскости их офигенного State Management. Каждый выбирает для себя. Полтора года использования этой либы на пяти-шести проектах - полет нормальный. Немного пилим напильником, но не принципиально. Если что, мы не понаслышке знаем про Provider, Redux, setState (хехе), так что наш выбор управления состоянием осознанный.
GetX во Flutter: Строим Unidirectional Data Flow с Rx-переменными