Mapeador de dados Javascript / React

Sep 26 2020

Minha solução para implementar um status (string) combinando dois outros. Eu preciso declarar uma função que leva dois parâmetros (duas strings) e precisa retornar outro baseado na combinação dessas duas strings. Por ex:

carStatus(status, secondaryStatus) => string

em que secondaryStatus pode ter várias opções. Estou usando uma instrução if / else if que retorna um terceiro status de que preciso. Por exemplo, quando o status é 'ABERTO' e o status secundário é 'pagamento1' ou 'pagamento2' ou 'pagamento3', a função deve retornar uma nova string (status) como 'CONFIRMADO'. Então, minha solução neste momento seria algo assim:

carStatus = (status, secondaryStatus) => {
  if(status === 'OPEN' && (secondaryStatus === 'payment1' || 'payment2' || 'payment3')){
    return 'CONFIRMED';
  } else if(status === 'CANCELLED' && (secondaryStatus === 'payment4' || 'payment5' || 'payment6')){
    return 'REMOVED';
  } else if(status === 'REVIEW' && (secondaryStatus === 'payment2' || 'payment5' || 'payment5')){
    return 'CHECKED';
  }
}

<div>carStatus('OPEN', 'payment1')</div>

Em div deve ser processado como 'CONFIRMADO'.

Na minha implementação, terei que escrever outras 5 instruções if ... então talvez haja uma maneira mais limpa de implementar isso.

Qualquer ajuda será apreciada.

Respostas

3 CertainPerformance Sep 26 2020 at 22:01

Bug de condição Sua implementação atual tem um bug. Suas linhas como essas têm o problema:

(secondaryStatus === 'payment1' || 'payment2' || 'payment3')

JavaScript possui apenas operadores unários, operadores binários e um único operador ternário. Todos os operadores usados ​​acima são operadores binários; duas expressões serão avaliadas em uma única expressão até que uma única seja deixada. Como ===tem precedência de operador maior que ||, seu código é equivalente a:

(secondaryStatus === 'payment1' || 'payment2' || 'payment3')

(trueOrFalse || 'payment2' || 'payment3')

Os payment2e payment3não são comparados secondaryStatus, e se secondaryStatusnão forem payment1, toda a expressão será avaliada como 'payment2'um valor verdadeiro (porque ||será avaliado como o segundo valor se o primeiro for falsey):

// || operates left-to-right:

(trueOrFalse || 'payment2' || 'payment3')

((false || 'payment2') || 'payment3')

(('payment2') || 'payment3')

// payment2 is truthy, so the `||` evaluates to it:
('payment2')

Para corrigir a lógica, use uma matriz em vez disso e verifique o status em relação a cada elemento da matriz.

Erro de digitação? Você tem (secondaryStatus === 'payment2' || 'payment5' || 'payment5'), com payment5repetido duas vezes. Você quis dizer outra coisa, como payment9?

Os nomes carStatus não contêm o status do carro, como pareceria conter; é uma função que, quando chamada, retorna o status do carro. Ele também usa um statusparâmetro nomeado de maneira semelhante e confusa . Chame-os de outra coisa, se possível: talvez getCarStatuse qualquer coisa mais específica que o statusparâmetro represente. Talvez chamar secondaryStatus: paymentType.

DRY Você também deseja tornar o código mais DRY, o que se encaixa bem com a ideia de usar arrays. Você pode usar um objeto, cujas chaves são o status necessário e cujos valores são os secondaryStatusvalores possíveis , bem como o valor de retorno, se secondaryStatusfor encontrado.

Além disso, como todas as strings de pagamento terminam em um número, e esse número é a única coisa que muda, use esse número para configurar o objeto de configuração em vez das paymentstrings completas :

const statusOptions = {
    OPEN:      { paymentNumbers: [1, 2, 3], status: 'CONFIRMED' },
    CANCELLED: { paymentNumbers: [4, 5, 6], status: 'REMOVED' },
    REVIEW:    { paymentNumbers: [2, 5], status: 'CHECKED' },
};
// ...
getCarStatus = (status, paymentType) => {
    const possibleOption = statusOptions[status];
    if (possibleOption) {
        const paymentNumber = Number(paymentType.match(/\d+$/)[0]);
        if (possibleOption.paymentNumbers.includes(paymentNumber)) {
            return possibleOption.status;
        }
    }
}

Snippet ao vivo:

const statusOptions = {
    OPEN:      { paymentNumbers: [1, 2, 3], status: 'CONFIRMED' },
    CANCELLED: { paymentNumbers: [4, 5, 6], status: 'REMOVED' },
    REVIEW:    { paymentNumbers: [2, 5], status: 'CHECKED' },
};
// ...
getCarStatus = (status, paymentType) => {
    const possibleOption = statusOptions[status];
    if (possibleOption) {
        const paymentNumber = Number(paymentType.match(/\d+$/)[0]);
        if (possibleOption.paymentNumbers.includes(paymentNumber)) {
            return possibleOption.status;
        }
    }
};

console.log(
  getCarStatus('OPEN', 'payment3'),
  getCarStatus('REVIEW', 'payment2')
);

Tipo de componente Parece que você está usando um componente de classe. React recomenda que você experimente usar componentes funcionais em um novo código; eles dizem que são um pouco mais fáceis de trabalhar e entender do que componentes baseados em classe na maioria das circunstâncias, e eu concordo. Tente usar componentes funcionais, se ainda não o fez, talvez goste deles.