1
votes

Réagissez au problème des hooks en passant la valeur || defaultValue et compteur de mise à jour

Trouvez ci-dessous des exemples de codes et une capture d'écran.

Deux questions:

  1. Le compteur ne se met pas à jour correctement, est-il permis d'écrire quelque chose comme setCounter ((prev) => {return {counter: prev.counter - value || 1 }}); ?

  2. setCounter (compteur + valeur || 1) Quelle est la bonne manière pour cela pour fonctionner, utilisez 1 dans les cas où une valeur réelle manque?

Trouvez ci-dessous des exemples de codes et de capture d'écran.

const Counter = (props) => {
  const [counter, setCounter] = useState(0);

  const handleCounterChange = (action, value) => {
    switch (action) {
      case "+":
        setCounter(counter + value || 1);
        break;
      case "-":
        setCounter(counter - value || 1);
        break;
      default:
        setCounter(counter + value || 1);
        break;
    }
  };

  return (
    <div className={classes.Counter}>
      <CounterOutput value={counter} />
      <CounterControl
        label="+"
        clicked={() => handleCounterChange("+")}
      />
      <CounterControl
        label="-"
        clicked={() => handleCounterChange("-")}
      />
      <CounterControl
        label="+ 5"
        clicked={() => handleCounterChange("+", 5)}
      />
      <CounterControl
        label="- 5"
        clicked={() => handleCounterChange("-", 5)}
      />
    </div>
  );
};

export default Counter;

entrez la description de l'image ici


0 commentaires

3 Réponses :


2
votes

Le problème avec setCounter (compteur + valeur || 1); est que JS essaiera d'abord de calculer compteur + valeur puis le test booléen. Par exemple, si la valeur de votre compteur est 1 et que vous soustrayez une valeur de 1 , le résultat est 0 , ce qui est faux, alors 1 sera sauvegardé comme nouvelle valeur du counter . Ce n'est probablement pas ce que vous voulez.

const handleCounterChange = (action, value = 1) => {
  switch (action) {
    case "+":
      setCounter(counter => counter + value);
      break;
    case "-":
      setCounter(counter => counter - value);
      break;
    default:
      // ignore, i.e. don't update state at all
      break;
  }
};

Vous pouvez cependant regrouper la priorité, c'est-à-dire counter + (value || 1) .

const handleCounterChange = (action, value = 1) => {
  switch (action) {
    case "+":
      setCounter(counter => counter + value);
      break;
    case "-":
      setCounter(counter => counter - value);
      break;
    default:
      setCounter(counter => counter + value);
      break;
  }
};

Si vous souhaitez simplement fournir une valeur par défaut de 1 pour valeur , vous pouvez le faire dans la signature. Si la valeur n'est pas définie, la valeur 1 lui sera attribuée. Et utilisez une mise à jour de l'état fonctionnel.

console.log(100 + (undefined || 1)); // 101

Une note complémentaire à propos de ce modèle de type "réducteur" est de renvoyer l'état existant si l'action n'est pas celle que vous gérez spécifiquement.

console.log(100 + undefined || 1); // expect 101 but result is 1
console.log(1 + -1 || 1); // expect 0 but result is 1


0 commentaires

0
votes

Ce n'est pas une réponse en soi, mais ne compliquez pas trop votre code avec cette fonction supplémentaire inutile. Votre logique est si simple, l'ajout de cette fonction supplémentaire la rend plus complexe à lire et ajoute une logique étrange (à quoi sert la valeur par défaut?)

  const change = by => () => setCounter(count => count+by)

  return (
    <div className={classes.Counter}>
      <CounterOutput value={counter} />
      <CounterControl
        label="+"
        clicked={change(1)}
      />
      <CounterControl
        label="-"
        clicked={change(-1)}
      />
      <CounterControl
        label="+ 5"
        clicked={change(5)}
      />
      <CounterControl
        label="- 5"
        clicked={change(-5)}
      />
    </div>
  );

Si vous voulez le sécher un peu plus, vous pouvez faites toujours quelque chose comme ceci:

  return (
    <div className={classes.Counter}>
      <CounterOutput value={counter} />
      <CounterControl
        label="+"
        clicked={() => setCounter(state => state+1)}
      />
      <CounterControl
        label="-"
        clicked={() => setCounter(state => state-1)}
      />
      <CounterControl
        label="+ 5"
        clicked={() => setCounter(state => state+5)}
      />
      <CounterControl
        label="- 5"
        clicked={() => setCounter(state => state-5)}
      />
    </div>
  );


0 commentaires

2
votes

Il y a quelques excellents refactors proposés ici. Je voudrais vraiment lire les suggestions et faire un refactor.

Quant à la cause de votre compteur imprévisible, en supposant que les arguments de clic entrent dans votre fonction de mise à jour d'état, il y a un problème d'ordre des opérations. Considérez cette situation.

La valeur est non définie

De la façon dont le code ci-dessus est écrit, lorsque la valeur est non définie , nous espère ajouter un nombre de valeur à l'état compteur . En raison de l'ordre des opérations, ce n'est pas ce qui se passe. Ce bogue se cache à la vue car souvent valeur et compteur sont tous les deux 1 , il semble donc que l'état ne change pas.

> counter + (value || 100)
101

Cette dernière déclaration dit "additionner le compteur plus undefined " qui est NaN et également faux. Le résultat dans ce cas sera toujours l'autre côté de l'instruction 'ou', 100 .

L'utilisation de parenthèses change l'ordre des opérations et crée le comportement souhaité. p>

> let value = undefined
undefined
> let counter = 1
undefined
> counter + value || 100
100


0 commentaires