useReducer est généralement préférable à usester lorsque vous avez une logique d'état complexe qui implique plusieurs sous-valeurs ou lorsque l'état suivant dépend de la précédente. useEducer vous permet également d'optimiser les performances des composants qui déclenchent des mises à jour approfondis, car vous pouvez passer une dépêche vers le bas au lieu de rappels.
(Citation de - https://reactjs.org/docs/hooks-reference.html#useraducer )
Je suis intéressé par la partie audacieuse, qui indique que useReducer
doit être utilisé au lieu de useState
lorsqu'il est utilisé dans des contextes.
J'ai essayé les deux variantes, mais ils ne semblent pas différer.
La façon dont j'ai comparé les deux approches était la suivante:
const [state, updateState] = useState();
const [reducerState, dispatch] = useReducer(myReducerFunction);
Je suis passé chacune une fois à un objet contextuel, qui était consommé dans un enfant plus profond (je viens de faire des tests séparés, remplaçant la valeur par la fonction que je voulais tester).
<ContextObject.Provider value={updateState // dispatch}>
L'enfant contenait ces fonctions
const updateFunction = useContext(ContextObject);
useEffect(
() => {
console.log('effect triggered');
console.log(updateFunction);
},
[updateFunction]
);
Dans les deux cas, lorsque le parent remonté (en raison d'un autre changement d'état local), l'effet n'a jamais couru, indiquant que la fonction de mise à jour n'est pas modifiée entre les rendus. Est-ce que je lis la phrase audacieuse dans la devis ne va pas? Ou y a-t-il quelque chose que je suis négligeant?
Si vous créez un rappel sur le rendre et transmettez-le à un composant enfant, les accessoires de cet enfant vont changer. Cependant, un composant régulier sera répercuter (à la DOM virtuelle) lorsque le parent rend les propulseurs, même les accessoires restent les mêmes. L'exception est un compromis de classe qui implémente les outils de fonctionnement et compare des accessoires (tels qu'un purecomonent).
Il s'agit d'une optimisation et vous ne devriez en vous soucier que si la détermination de la composante enfant nécessite un calcul important (si vous le rendez au même écran plusieurs fois, ou si cela nécessitera un titre profond ou significatif).
Si tel est le cas, vous devez vous en assurer: 1. Votre enfant est un composant de classe qui s'étend surtecomponent 2. Évitez de transmettre une fonction nouvellement créée comme un accessoire. Au lieu de cela, passez l'expédition, le setter est revenu de React.UseState ou d'un setter personnalisé mémo.
Bien que je ne recommanderais pas de construire un setter mémo unique pour un composant spécifique (il y a quelques points à rechercher), vous pouvez utiliser un crochet général qui prend soin de la mise en œuvre pour vous.
Voici un exemple de crochet UTILOBJSTATE, qui fournit une API facile et qui ne provoquera pas de redevances supplémentaires.
const useObjState = initialObj => {
const [obj, setObj] = React.useState(initialObj);
const memoizedSetObj = React.useMemo(() => {
const helper = {};
Object.keys(initialObj).forEach(key => {
helper[key] = newVal =>
setObj(prevObj => ({ ...prevObj, [key]: newVal }));
});
return helper;
}, []);
return [obj, memoizedSetObj];
};
function App() {
const [user, memoizedSetUser] = useObjState({
id: 1,
name: "ed",
age: null,
});
return (
<NameComp
setter={memoizedSetUser.name}
name={user.name}
/>
);
}
const NameComp = ({name, setter}) => (
<div>
<h1>{name}</h1>
<input
value={name}
onChange={e => setter(e.target.value)}
/>
</div>
)