DEV Community

Como funcionam Observables no KnockoutJs

Este conteúdo é basicamente uma tradução dos materiais originais. A intenção é adquirir aprendizado sobre o KnockoutJs para Magento 2 e criar conteúdo em português sobre KnockouJs.

Documentação


Observables

O KnockoutJs introduz o conceito de observables, que são propriedades que podem ser monitoradas e atualizadas automaticamente quando seus valores mudam. Essa funcionalidade permite que a interface do usuário reaja dinamicamente a alterações nos dados do Model.

Para criar um observable no KnockoutJs, é possível utilizar a função ko.observable() e atribuir um valor inicial a ela. Para acessar o valor atual de um observable, é possível tratá-lo como uma função. Para só observar algo sem um valor inicial, basta chamar a propriedade Observable sem parâmetros.

let myObservable = ko.observable('Inicial');

console.log(myObservable()); // Irá imprimir 'Inicial'

myObservable('Novo valor');
console.log(myObservable()); // Irá imprimir 'Novo valor'
Enter fullscreen mode Exit fullscreen mode
  • ko.isObservable: retorna true para observables, observables arrays e todos os computed observables;
  • ko.isWritableObservable: retorna true para observables, observable arrays e writable computed observables.

Subscriptions

As subscriptions em observables são mecanismos que permitem que seja notificado sempre que o valor de um observable é alterado. Elas são essenciais para acompanhar as mudanças nos observables e reagir a essas mudanças, atualizando a interface do usuário ou executando outras ações quando necessário.

O método subscribe() ***recebe uma função de *callback que será executada sempre que o valor do observable for modificado. A função de callback recebe como argumento o novo valor do observable. Esta função aceita três parâmetros: callback é a função que é chamada sempre que a notificação acontece, target (opcional) define o valor disso na função callback e event (opcional; o padrão é change) é o nome do evento para receber notificação.

let myObservable = ko.observable(0);

// Criando uma subscription no observable
myObservable.subscribe(function (newValue) {
  console.log('Novo valor do observable:', newValue);
}, scope, event);
Enter fullscreen mode Exit fullscreen mode
  1. change: Esse é o evento padrão que aciona a subscription sempre que o valor do observable é alterado. É o evento mais comum e é usado quando nenhum outro evento é especificado explicitamente;
  2. beforeChange: Esse evento é acionado antes que o valor do observable seja alterado. A função de callback receberá dois argumentos: o valor atual do observable e o valor proposto (novo) que será atribuído ao observable. Isso permite que seja executado ações com base no valor atual antes de ser alterado;
  3. afterChange: Esse evento é acionado após o valor do observable ser alterado. A função de callback receberá dois argumentos: o valor anterior do observable (antes da alteração) e o novo valor que foi atribuído ao observable. É útil quando você precisa reagir a uma mudança específica após ela ter ocorrido.
  4. arrayChange: Esse evento é específico para Observables Arrays. Ele é acionado quando há uma alteração em um array observable, como adição, remoção ou substituição de itens no array. A função de callback recebe quatro argumentos: os itens afetados (added, deleted, status e index).

Outro ponto importante e que é possível armazenar a subscription em uma variável e, se necessário cancelar a inscrição usando o método dispose(). Isso é útil quando se deseja desativar temporariamente ou permanentemente a atualização da interface do usuário em resposta a alterações nos observables.

const myObservable = ko.observable();
const subscription = myObservable.subscribe(function (newValue) {
  console.log('Novo valor do observable:', newValue);
});

myObservable(42); // A subscription será acionada e imprimirá "Novo valor do observable: 42" no console.

// Cancelando a subscription
subscription.dispose();

myObservable(100); // Nada será impresso no console, pois a subscription foi cancelada.
Enter fullscreen mode Exit fullscreen mode

Métodos para determinar tipos de observables

  1. isObservable(): Este método é usado para verificar se um valor é um observable. Ele retorna true se o valor for um observable (observable, observableArray, computed ou writable computed), e false caso contrário.
  2. isWritableObservable(): Este método verifica se um valor é um observable gravável (writable observable). Ele retorna true se o valor for um writable observable e false caso contrário;
  3. isComputed(): Este método é usado para verificar se um valor é um Computed Observable. Ele retorna true se o valor for um Computed Observable e false caso contrário;
  4. isPureComputed(): Este método verifica se um valor é um Pure Computed Observable. Um Pure Computed Observable é aquele que depende apenas de outros pure observables e não possui lógica interna de gravação. Ele retorna true se o valor for um Pure Computed Observable e false caso contrário.

Observables Arrays

Observables Arrays são uma extensão dos observables e são usados para lidar com listas de dados que precisam ser observáveis. Ao contrário de um array JavaScript padrão, um Observable Array permite que se acompanhe automaticamente as mudanças nos dados da lista e atualize a interface do usuário de forma reativa.

let myObservableArray = ko.observableArray(['Maçã', 'Banana', 'Laranja']);

myObservable.push('Limão');
Enter fullscreen mode Exit fullscreen mode

Os Observables Arrays possuem métodos específicos que permitem adicionar, remover e manipular itens de forma reativa. Alguns desses métodos são:

  • indexOf(value): Retorna o índice do primeiro item do array que é igual ao seu parâmetro, ou o valor -1 se nenhum valor correspondente for encontrado.
  • push(item): Adiciona um novo item ao final do array;
  • pop(): Remove e retorna o último item do array;
  • shift(): Remove e retorna o primeiro item do array;
  • unshift(item): Adiciona um novo item ao início do array;
  • remove(item): Remove um item específico do array;
  • removeAll([parametro]): Remove todos os itens do array, podendo receber um parametro em forma de array que removera os itens dentro do(s) parametro(s) passados;
  • replace(oldItem, newItem): Substitui o item passado no primeiro parâmetro pelo segundo parâmetro;
  • reverse(): Altera a ordem dos itens do array original e atualiza a interface do usuário para refletir a nova ordem;
  • reversed(): Retorna uma cópia do array revertida;
  • splice(index, count, items): Permite adicionar ou remover itens em uma posição específica do array;
  • slice(): Retorna uma cópia de um subconjunto do array, começando no índice start e indo até o índice end-1. Os valores de start e end são opcionais, e se não forem fornecidos;
  • sort(): Determina a ordem dos itens. Se a função não for fornecida, o método ordena os itens em ordem alfabética crescente (para strings) ou em ordem numérica crescente (para números);
  • sorted(): Retorna uma cópia do array ordenado. É preferível ao método sort(), caso seja necessário não alterar o observable array original, mas precisa exibi-lo em uma ordem específica;

Para funções que modificam o conteúdo da matriz, como push e splice, os métodos de KO acionam automaticamente o mecanismo de rastreamento de dependência para que todos os ouvintes registrados sejam notificados da alteração e sua interface seja atualizada automaticamente, o que significa que há uma diferença significativa entre usar Métodos de KO (observableArray.push(...), etc) e métodos de array nativos de JavaScript (observableArray().push(...)), já que os últimos não enviam nenhuma notificação aos assinantes do array de que seu conteúdo foi mudado.

Embora seja possível utilizar subscribe e acessar um observableArray como qualquer outro observável, o KnockoutJs também fornece um método super rápido para descobrir como um array observável foi alterado (quais itens acabaram de ser adicionados, excluídos ou movidos). É possível se inscrever nas alterações de array da seguinte maneira:

const obsArray = ko.observableArray(['Maçã', 'Banana', 'Laranja']);
obsArray.subscribe(fn, thisArg, "arrayChange");
Enter fullscreen mode Exit fullscreen mode

Computed Observables

Computed Observables são funções que dependem de um ou mais observables e serão atualizadas automaticamente sempre que qualquer uma dessas dependências alterar. A função será chamada uma vez a cada vez que qualquer uma de suas dependências alterar, e qualquer valor que retornar será passado para os observables, como elementos de interface do usuário ou outros computed observables.

A principal diferença entre os Computed Observables e os Observables é que os Computed Observables não armazenam diretamente um valor; em vez disso, eles dependem de outros observables para calcular seu valor. Isso significa que o valor de um Computed Observable é sempre atualizado automaticamente quando qualquer um dos observables de que ele depende é modificado.

function AppViewModel() {
    this.firstName = ko.observable('Bob');
    this.lastName = ko.observable('Smith');

        this.fullName = ko.computed(function() {
        return this.firstName() + " " + this.lastName();
    }, scope);
}
Enter fullscreen mode Exit fullscreen mode

Métodos de um Computed Observable

  1. dispose(): Este método é usado para descartar (limpar) um Computed Observable quando ele não é mais necessário. Ele remove todas as assinaturas e dependências associadas ao Computed Observable;
  2. extend(): Este método permite adicionar extensores personalizados a um Computed Observable. Os extensores são funções que podem modificar o comportamento do Computed Observable;
  3. getDependenciesCount(): Este método retorna o número de observables dependentes do Computed Observable;
  4. getDependencies(): Este método retorna uma matriz contendo os observables que são dependências do Computed Observable;
  5. getSubscriptionsCount(): Este método retorna o número de assinaturas atuais do Computed Observable;
  6. isActive(): Este método retorna um valor booleano que indica se o Computed Observable está atualmente ativo (um Computed Observable está ativo se estiver em processo de avaliação devido a uma mudança em suas dependências);
  7. peek(): Este método é semelhante ao operador de parênteses () usado para acessar o valor atual de um Computed Observable. No entanto, o método peek não cria uma dependência entre o Computed Observable e o local em que é chamado;
  8. subscribe(): Este método permite a inscrição para receber notificações sempre que o valor do Computed Observable for alterado.

this

O segundo parâmetro para ko.computed define o valor this ao avaliar o observable calculado. Sem passá-lo, não seria possível fazer referência a this.firstName() ou this.lastName().

Há uma convenção que evita a necessidade de rastrear isso completamente: se o construtor do seu viewmodel copiar uma referência a this em uma variável diferente (tradicionalmente chamada de self), será possível usar self em todo o seu viewmodel e não precisa se preocupar com isso redefinido para se referir a outra coisa.

function AppViewModel() {
    var self = this;
    self.firstName = ko.observable('Bob');
    self.lastName = ko.observable('Smith');

    self.fullName = ko.computed(function() {
        return this.firstName() + " " + this.lastName();
    }, this);

    self.fullName = ko.computed(function() {
        return self.firstName() + " " + self.lastName();
    });
}
Enter fullscreen mode Exit fullscreen mode

Como self é capturado no fechamento da função, ele permanece disponível e consistente em qualquer função aninhada, como o avaliador do computed observable. Essa convenção é ainda mais útil quando se trata de manipuladores de eventos.

Pure computed observables

Caso um computed observable simplesmente calcule e retorne um valor com base em algumas dependências observáveis, é melhor declará-lo como ko.pureComputed em vez de ko.computed.

this.fullName = ko.pureComputed(function() {
    return this.firstName() + " " + this.lastName();
}, scope);
Enter fullscreen mode Exit fullscreen mode

Quando um computed observable é declarado como pure, seu avaliador não modifica diretamente outros objetos ou estado, o KnockoutJs pode gerenciar com mais eficiência sua reavaliação e uso de memória. O KnockoutJs irá suspendê-lo ou liberá-lo automaticamente se nenhum outro código tiver uma dependência ativa dele.

Writable Computed Observables

Os Writable Computed Observables são uma extensão dos Computed Observables que permitem a criação de computed observables que podem ser atualizados tanto por meio da leitura quanto da gravação. Diferente dos Computed Observables convencionais, que apenas calculam seu valor com base em outros observables e não armazenam diretamente um valor, os Writable Computed Observables podem armazenar um valor e também fornecem uma função para atualizar esse valor quando necessário.

Para criar um Writable Computed Observable, é necessário utilizar a função ko.computed com um objeto de configuração que contém duas propriedades principais: read e write. A propriedade read contém a função de cálculo para determinar o valor do observable, enquanto a propriedade write contém a função que é chamada quando deseja-se atualizar o valor do observable.

Top comments (0)