Является ли привязка данных в шаблоне из внешнего объекта плохой практикой?

#angular #data-binding

#angular #привязка данных

Вопрос:

Допустим, у меня есть хранилище (большой одноэлементный объект), где я сохраняю общее состояние приложения. При необходимости это хранилище вводится в компоненты. Однако есть компоненты, которые используют только одно свойство из хранилища и используют его для условных выражений в своих шаблонах (конечно, только для чтения).

Есть ли здесь предпочтительная практика? Должен ли я использовать свойство непосредственно из встроенного хранилища

 class MyComponent {

    constructor(private store: Store) {}
}

// template

<div *ngIf="store.someFlag">...</div>
  

или я должен создать частное свойство в компоненте, а затем использовать его в шаблоне?

 class MyComponent {

    someFlag: boolean;

    constructor(private store: Store) {
        this.someFlag = store.someFlag;
    }
}

// template

<div *ngIf="someFlag">...</div>
  

Меня больше всего беспокоит производительность — влияет ли доступ к данным из большого объекта в шаблоне на производительность циклов обнаружения угловых изменений?

Ответ №1:

Прежде всего, я предпочитаю использовать store.someFlag напрямую, поскольку это свойство может быть изменено, и оно будет немедленно отражено на странице, тогда как если вы назначите его локальной переменной, эта переменная не изменится со временем (если вы что-то не сделаете). Присвоение переменной имеет смысл, если вы планируете изменять это значение локально и не хотите, чтобы изменение распространялось обратно в хранилище. Я делаю это, когда хочу, чтобы дата моего приложения изначально применялась к этому экрану, но экран может изменить уже локальную дату обратно и принудительно по желанию пользователя.

И, во-вторых, если вы планируете использовать хранилище в шаблоне, убедитесь, что вы делаете его общедоступным в конструкторе (не частным), поскольку он не будет соответствовать более строгим правилам производства.

 class MyComponent {

    constructor(public store: Store) {}
}
  

Ответ №2:

Я хотел бы указать на другую проблему, которую я вижу в подходе: Вы привязываете компоненты к тому, как вы реализовали глобальное состояние. Делая это, вы тесно связываете их.

Допустим, вы хотите изменить структуру своего глобального состояния. Например, вы хотите переместить объект на один уровень ниже в иерархии состояния. При вашем подходе вам придется касаться каждого компонента, возможно, несколько раз для каждого компонента.

Я бы рекомендовал оставить компоненты как можно более глупыми. Дайте им реальный объект, который они могут прочитать или изменить как @Input() . Пусть они работают над этим. Добавьте @Output() , когда / если объект изменится.

Таким образом, вы более четко разделяете проблемы: компонентам просто нужно знать, как работать с одним конкретным классом, а не с общим состоянием.

Комментарии:

1. Но что, если мне понадобится это состояние примерно во всех компонентах, не станет ли утомительным и сложным поддерживать свойство /@Input и событие /@Output?

2. Если это «большой одноэлементный объект», как указано в вопросе, и вам нужен этот большой одноэлементный объект в каждом компоненте, я думаю, что что-то не так с архитектурой. В этом случае, да, это было бы утомительно и сложно, но это было бы просто указателем на проблему в другом месте.

3. Да, это правда, что для всех компонентов не требуется один и тот же «большой одноэлементный объект», но не для компонентов с уровнем иерархии более 3 . Существуют ли какие-либо другие возможные способы обмена данными на 4-5 уровень ниже по иерархии компонентов, кроме ввода / вывода?

4. Вы, конечно, можете предоставить своим компонентам большую часть своего состояния. Это всегда компромисс, когда вам нужно найти наилучший вариант для вашего конкретного варианта использования. Я бы просто избегал передачи одного и того же гигантского объекта состояния каждому компоненту и тем самым терял а) гибкость, б) тестируемость, в) обзор.

Ответ №3:

 class MyComponent {

    constructor(public store: Store) {}
}

// template

<div *ngIf="store.someFlag">...</div>
  

Это будет лучшим вариантом. Как если бы вы создали локальную копию этой переменной, то при обнаружении изменений может случиться так, что ваше значение при изменении из другого модуля / компонента не будет отражено в этом компоненте.