useState
déclenche toujours une mise à jour même lorsque les valeurs des données n'ont pas changé.
Voici une démo fonctionnelle du problème: démo
J'utilise le crochet useState
pour mettre à jour un objet et j'essaie de le faire mettre à jour uniquement lorsque les valeurs de cet objet changent. Parce que React utilise l'algorithme de comparaison Object.is pour déterminer quand il doit être mis à jour; les objets avec des valeurs équivalentes entraînent toujours le nouveau rendu du composant car ce sont des objets différents .
Ex. Ce composant sera toujours rendu même si la valeur de la charge utile reste comme { foo: 'bar' }
const UseStateWithNewObject = () => {
const [payload, setPayload] = useState({});
useEffect(
() => {
setInterval(() => {
setPayload({ foo: 'bar' });
}, 500);
},
[setPayload]
);
renderCountNewObject += 1;
return <h3>A new object, even with the same values, will always cause a render: {renderCountNewObject}</h3>;
};
Y a-t-il un moyen pour que je puisse implémenter quelque chose comme shouldComponentUpdate
avec des crochets pour dire à réagir de ne re-rendre mon composant que lorsque les données changent?
Dans le cas où vous vérifiez les modifications sur les accessoires de type objet ou tableau d'objets, je suggère d'utiliser JSON.stringify sur useEffect deps. C'est assez simple.
const obj = {foo: 'bar'}
const [state, setState] = useState(obj)
useEffect(() => {
setState(obj)
},[JSON.stringify(obj)])
La solution générique à cela, qui n'implique pas l'ajout de logique à vos effets, consiste à diviser vos composants en:
React.memo
Votre composant stupide peut être pur (comme s'il avait shouldComponentUpdate
implémenté et votre composant de gestion d'état intelligent peut être "stupide" et ne pas s'inquiéter de la mise à jour de l'état à la même valeur.
Exemple:
export default function Foo() {
const [state, setState] = useState({ foo: "1" })
const handler = useCallback(newValue => setState({ foo: newValue }))
return (
<div>
<SomeWidget onEvent={handler} />
Value: {{ state.foo }}
</div>
)
const FooChild = React.memo(({foo, handler}) => {
return (
<div>
<SomeWidget onEvent={handler} />
Value: {{ state.foo }}
</div>
)
})
export default function Foo() {
const [state, setState] = useState({ foo: "1" })
const handler = useCallback(newValue => setState({ foo: newValue }))
return <FooChild handler={handler} foo={state.foo} />
}
Cela vous donne la séparation de la logique que vous recherchez.