React, console.log et render affichent des valeurs différentes
Il semble que l' objet connecté à la console ne correspond pas à ce qui est affiché sur le HTML , je suis déconcerté par cet exemple simple ci-dessous. Ici, le bouton change l'ordre du tableau et React semble rendre la liste précédente.
=== Mise à jour 3 ====
Le cuprite est la compassion d'objet où setState(list=>list.push(12))mute la liste mais ne déclenchera pas setState car l'id de la liste est toujours le même.
Si vous mettez à jour un State Hook à la même valeur que l'état actuel, React renflouera sans rendre les enfants ni déclencher les effets. (React utilise l'algorithme de comparaison Object.is.) React useState doc
=== Mise à jour 2 ====
Je pense avoir trouvé la solution. Le coupable semble être la mutabilité des objets et la solution de contournement consiste à créer une copie complète de la liste triée dans Solution Sandbox . Je crois que j'ai trouvé un comportement non défini REACT, puisque la mutabilité de la liste ne devrait pas causer des différences dans console.log(list)et <h1>list</h1>montré dans l'image ci - dessous. Corriger la modification des tableaux d'état dans ReactJS
=== Mise à jour 1 ====
Sandbox qui contient le même code que celui illustré ci-dessous.
Il n'y a rien de mal avec ma fonction de tri! S'il est croissant, l'élément le plus petit doit venir en premier, ce qui signifie que la fonction de comparaison (e1,e2)=>e1-e2est correcte.
Si compareFunction (a, b) renvoie moins de 0, triez a en un index inférieur à b (c'est-à-dire que a vient en premier). Fonction de comparaison Mozilla
const {useState, useEffect, useReducer} = React;
function App() {
const [list, setList] = useState([0,1]);
const [isAscending, toggle] = useReducer(isAscending=>!isAscending, true);
// update the order of the list
useEffect(()=>{
if (isAscending) {
setList(list.sort((e1,e2)=>e1-e2));
} else {
setList(list.sort((e1,e2)=>e2-e1));
}
},[list, isAscending]);
// render
return (
<div>
{console.log("list[0] should be",list[0])}
<button onClick={toggle}>{isAscending?"Ascending":"Descending"}</button>
<h1>list[0]: {list[0]}</h1>
</div>
)
}
ReactDOM.render(<App/>, document.querySelector('.App'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div class='App'/>
Réponses
selon MDN, la fonction de tri javascript mute le tableau.
La méthode sort () trie les éléments d'un tableau sur place et retourne le tableau trié.
quand vous écrivez:
setList(list.sort((e1, e2) => e1 - e2));
vous faites muter la liste avant que setList la mute.
setList vérifie si la valeur donnée est différente de la précédente puis rend.
mais setList ne voit pas de différence puisque la valeur de la liste est déjà mise à jour par la méthode de tri.
à cause de cela, le rendu semble un pas en arrière.
vous devriez donc écrire:
setList([...list].sort((e1, e2) => e1 - e2));
encore une chose:
je pense que tu devrais changer
{isAscending ? "Ascending" : "Descending"}
à
{isAscending ? "Descending" : "Ascending"}
puisqu'il s'agit d'un bouton à bascule
Votre commande initiale est d'ordre croissant. Lorsque vous cliquez sur le bouton, la première fois pour basculer l'ordre que vous souhaitez passer de l'ordre croissant à l'ordre décroissant.
Ce qui signifie
if (isAscending) {
// Logic for descending should come here
setList(list.sort((e1, e2) => e2 - e1));
} else {
// Logic for ascending should come here
setList(list.sort((e1, e2) => e1 - e2));
}
Vérifiez le code ici et faites-moi savoir si c'est ce que vous recherchiez. Bac à sable de code: la liste triée n'est pas rendue
Vous avez la fermeture sur la listvaleur lors du useEffectrappel, vous devez l'ajouter à votre tableau dep:
function App() {
const [list, setList] = useState([0, 1]);
const [isAscending, toggle] = useReducer((isAscending) => !isAscending, true);
useEffect(() => {
setList(list.sort((e1, e2) => (!isAscending ? e1 - e2 : e2 - e1)));
}, [list, isAscending]);
return (
<div>
<button onClick={toggle}>
{isAscending ? "Ascending" : "Descending"}
</button>
<pre>{JSON.stringify(list)}</pre>
</div>
);
}
Notez que si vous en avez,
eslintvous devriez recevoir un avertissement à ce sujet.
https://codesandbox.io/s/react-template-forked-08eft?file=/index.js:99-684
J'ai un peu simplifié votre extrait.
Vous utilisiez étrangement les deux useStateet useReducertandis que le second est une alternative au premier.
useReducer est généralement préférable à useState lorsque vous avez une logique d'état complexe qui implique plusieurs sous-valeurs ou lorsque l'état suivant dépend du précédent.
Cité de la documentation Reactjs
const {useReducer} = React;
function App() {
const list=[0,1]
const [isAscending, toggle] = useReducer(isAscending=>{
if (isAscending) {
list.sort((e1,e2)=>e2-e1)
} else {
list.sort((e1,e2)=>e1-e2)
}
return !isAscending
}, list);
// render
return (
<div>
{console.log("list[0] should be",list[0])}
<button onClick={toggle}>{isAscending?"Ascending":"Descending"}</button>
<h1>list[0]: {list[0]}</h1>
</div>
)
}
ReactDOM.render(<App/>, document.querySelector('.App'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div class='App'/>
Voici donc listest le initialStatel'exemple de la documentation. Et la logique pour réorganiser la liste, qui est maintenant très simple, se trouve à l'intérieur de la fonction de réduction.
En espérant que cela aide! ;)