Зачем нам нужны две функции: update() и set() в сигналах Angular?

Я читал о сигналах в Angular, и есть два способа изменить текущее значение: с помощью set() и update().

Angular адаптировал Signals к своей структуре и начал создавать набор новых функций, которые используют Signals в качестве краеугольного камня. Использование update позволяет нам получить доступ к текущему значению сигнала, а set позволяет нам установить новое значение, не заботясь о текущем значении.

Что меня озадачивает, так это то, что я не понимаю, зачем нужны оба (хотя вижу, что каждый можно использовать). Понятно, что могу.Но почему?

Допустим, мы определили такой экземпляр.

siggy = signal(4);

Затем мы можем установить абсолютное значение, используя оба следующих способа.

this.siggy.set(1337);
this.siggy.update((a) => 1337);

Но мы также можем использовать оба из них, чтобы установить относительный (изменить текущий).

this.siggy.set(this.siggy() + 1);
this.siggy.update((a) => a + 1);

Кажется излишним предлагать несколько способов достижения одного и того же результата. Такая избыточность является признаком плохого дизайна (или, возможно, синтаксического сахара для целей DX). Я ни в коем случае не утверждаю, что замечательные ребята из команды Angular создали плохой дизайн! И при этом я не вижу увеличения плавности хода. (На самом деле, даже в блоге Angular упоминается использование this.counter.set(this.counter()+1)...)

Мой вывод таков: есть (крайние) случаи, о которых я не знаю. Что мне не хватает?

редактировать

Я продолжал исследования и обнаружил еще более запутанные факты. Помимо set() и update(), есть еще mutate() (Вот вам и Полное руководство, большое спасибо). А этот можно использовать, как показано ниже (что я интуитивно и сделал).

let siggy = signal([1,2,3]);
...
this.siggy.mutate(a => a.push(4));

Он компилируется. Проблема в том, что он ничего не сделает: ни изменений, ни обновлений, ничего! Видимо, мне придется сделать так.

this.siggy.mutate(a => a = [...a, 4]);

Но для остальных это лишнее! Я понимаю (хотя и не согласен), что кто-то может захотеть использовать set() для обозначения замены, сохраняя при этом update() для изменений. Но даже в этом случае mutate() не приносит никакой дополнительной информации, поскольку это обновление (которое также устанавливает его).

Кажется, не хватает только siggy.alter(), siggy.change() и siggy.modify(). Мне пахнет рыбой. Я уверен, что это я не понимаю фактической причины, по которой требуются все установки/обновления/мутации.

Какая техническая причина? Что нельзя сделать с каждым из них?

Очевидно, вы могли бы использовать обновление, чтобы просто установить значение и игнорировать текущее значение. Но тогда есть а) неиспользуемая переменная и б) цель неясна, и мне, как разработчику, приходится проверять реальную логику внутри блока обновления (которая может быть более сложной, чем одна строка), чтобы понять, что обновление просто заданная операция. Просто наличие специального метода для этого случая кажется более кратким. Я чувствую, что у обоих есть свои варианты использования. И случай this.siggy.set(this.siggy() + 1); - пожалуйста, не делай этого. Он кажется ДЕЙСТВИТЕЛЬНО неуклюжим, и я бы не держал пари, что он будет работать так, как ожидалось :D

Loop 15.06.2024 20:24
здесь хороший дискурс о Сигналах. Во второй части говорится: «Хотя поверхность API имеет 3 различных метода (set, update, mutate) изменения значения сигнала, .set(newValue) — единственная фундаментальная операция, которая нам нужна в библиотеке. Остальные 2 метода: просто синтаксический сахар, удобные методы, которые можно выразить как .set».
Eliseo 17.06.2024 15:31

@Eliseo Это подтверждает мое впечатление. Тем не менее, я не понимаю, почему такая избыточность. Я вижу, как предлагает Loop выше, что это визуально указывает на сброс после изменения. Отлично. Не в моем вкусе, но я понимаю, что кто-то это оценит. Но почему два сокращения?! Меня это беспокоит. Меня это очень беспокоит.

Konrad Viltersten 17.06.2024 20:31
update() просто звонит set() внутрь: источник на GitHub так что на этот вопрос, вероятно, нет убедительного/эмпирического ответа, если только кто-то не сможет найти его в комментариях к соответствующим RFC от членов команды Angular.
D M 19.06.2024 16:15

Похоже, mutate() был полностью удален: CHANGELOG на GitHub.

D M 19.06.2024 16:17

Я предполагаю, что set(), вероятно, должна быть перегрузкой update() с параметром updater по умолчанию (текущее значение не требуется для определения нового значения). В результате у нас остались бы только update(T) и update(T -> T) (две перегрузки) и никаких set()/mutate(), что означало бы, что мутации можно обнаружить.

D M 19.06.2024 16:20

@DM Прежде всего: я никоим образом не притворяюсь, что знаю лучше, и у меня нет смелости критиковать замечательных разработчиков, создающих Angular. Я не в их лиге по любым меркам. Теперь, когда это совершенно ясно сказано: сигналы в Angular кажутся мне преждевременной эякуляцией. Эти многочисленные методы были удалены, избыточны и т. д. Кроме того, сигнал внутри компонента стал доступен в версии 16, а сигнал модели — в версии 18 (что мне потребовалось некоторое время, чтобы обнаружить). Такое ощущение, что кто-то из отдела маркетинга немного обрадовался. Нет, Буэно... Это так по-реакционно...

Konrad Viltersten 19.06.2024 17:17

Как показывает @DM в источнике, это то же самое. Представляю какую-то ностальгию по лямбда-функциям

Eliseo 21.06.2024 13:55
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
1
8
351
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Насколько я знал,

this.siggy.set(this.siggy() + 1); // Not a correct way to implement

и

this.siggy.update((a) => a + 1); // here `a` will be the existing value of `siggy`.

совершенно разные. Это не будет работать так, как вы предполагаете. Поскольку эти методы асинхронны, поведение будет другим.

Метод set заменит значение на старое. тогда как update будет изменять/обновлять старое значение.

Бывший:

this.siggy.update((a) => a + 1);
console.info(this.siggy()); // Here the value will not be latest one.

С тем же сценарием я столкнулся в React.js при использовании крючка useState, поэтому существуют отдельные методы update и set.

Вы говорите: «Поскольку эти методы асинхронны». На самом деле я думаю, что это не так, сигналы всегда синхронны (то есть одинаковы). Единственное это не написать а получить какую-то "лямбду"

Eliseo 21.06.2024 13:54

При всем уважении к вашему опыту, сравнивать Angular с React обычно очень плохая идея и легко приводит к путанице из-за ложного сходства концепций. Я не могу с уверенностью сказать, что set/update в сигналах Angular и состояниях Reacts принципиально отличаются, но, насколько я осмелюсь, я бы не стал считать их одинаковыми. Кроме того, мне интересно, почему вы имеете в виду, что первый образец является недействительным (или неправильным для реализации)? Это работает, и, согласно блогу Angular, когда я его читал, разницы не было. Вы предлагаете это с точки зрения синтаксиса React?

Konrad Viltersten 23.06.2024 15:50

«Метод set заменит значение на старое, тогда как обновление изменит/обновит старое значение». Это утверждение не имеет для меня смысла. Это просто разные слова для одного и того же события, не так ли? Установка совершенно нового значения и обновление старого значения до совершенно нового значения — это одна и та же операция, верно? Это не значит, что новое значение 7 волшебным образом помнит, что когда-то в его прежнем воплощении было -3. Чего нам здесь не хватает, пожалуйста? Это похоже на различие без разницы.

Konrad Viltersten 23.06.2024 15:53

Вы запрашиваете техническую необходимость, ведущую к решению иметь отдельные методы для работы с предыдущим значением и не работать с предыдущим значением, а просто переопределить его.

Судя по тому, что я знаю о самом JavaScript, и исходя из своего опыта работы с React, технически было возможно использовать одно и то же имя функции для обоих. В React вы можете сделать и то, и другое с помощью одной и той же функции, см. этот пример:

export default function MyComponent() {
  const [currentValue, setCurrentValue] = useState(0);

  const handleClick = () => {
    // version 1
    setCurrentValue(() => currentValue + 1)
    // version 2
    setCurrentValue((oldValue) => oldValue + 1)

  }

  return (<>
    {currentValue}
    <button onClick = {handleClick}>Add 1</button>
  </>);
}

Это сбивало меня с толку, когда я начал работать с React, потому что, имея функцию под названием «set», которая позволяла мне делать стилистически совершенно разные вещи, мне приходилось внимательно следить за тем, как она используется. Поэтому я лично считаю, что наличие более описательных названий для этих двух вещей имеет смысл и приводит к более выразительному и читаемому коду.

TLDR: Javascript позволяет переопределить. Поэтому нет технической необходимости использовать две отдельные функции. Разработчики Angular могли выбрать любую версию — иметь отдельные имена функций или переопределить их на основе их сигнатур. Как объяснялось выше, я думаю, что имеет смысл иметь разные функции для разных целей, чтобы все имело свое имя. Но в конечном счете это чистое предпочтение.

Этот вопрос касается Angular, а не React. Я думаю, что опасно рассматривать их как сопоставимые элементы, и то, что имеет смысл в React, не имеет смысла в Angular (чаще, чем люди ожидают). Я надеялся на техническое обоснование с точки зрения Angular, потому что не вижу в нем абсолютно нулевой выгоды. В React это, к сожалению, необходимо. Но, на мой взгляд (самоуверенный и предвзятый), это больше говорит о React... :)

Konrad Viltersten 23.06.2024 15:58
Ответ принят как подходящий

TL;DR: как вы упомянули, необходим только set, update был введен для удобства и mutate в конечном итоге был удален, по сути, так же, как set

Полное обсуждение можно посмотреть в RFC Signals API.

Ну... черт! Еженедельное разочарование. Я надеялся получить более глубокую техническую информацию, которая познакомит меня с внутренним устройством Angular. Такой большой ажиотаж напрасно. По крайней мере, я не знаю. Вот ваши 100 вкусняшек. Наслаждаться!

Konrad Viltersten 23.06.2024 16:00

Другие вопросы по теме