L'expérience du blogueur est encore superficielle, veuillez me corriger s'il y a une erreur
Un: useState
1. Comment utiliser
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
Comme on peut le voir à partir du code source de la définition de hook ci-dessus, le paramètre de la fonction hook useState est passé dans une valeur initiale (ou une fonction, qui obtient la valeur initiale après l'appel), et la valeur de retour est renvoyée au monde extérieur pour des opérations de lecture et d'écriture sur l'état (sous la forme d'un tableau) . L'exemple d'utilisation de base est le suivant:
const [state, setState] = useState(initialState);
2. Cas d'utilisation
Comme nous le savons tous, les composants de classe sont également appelés composants avec état et ont la capacité de gérer l'état. Avant que la fonction hook n'apparaisse, le composant fonction est également appelé composant sans état et n'a pas la capacité de gérer l'état. Jusqu'à ce que la fonction de crochet apparaisse, le composant de fonction a la capacité de gérer l'état. Voici une liste des différences dans l'implémentation de la gestion d'état entre les composants de classe et les composants de fonction (avec useState). Faites attention à l'initialisation de l' état et aux opérations de lecture et d'écriture de l' état de ces deux manières .
État de la gestion des composants de classe
import React from "react";
export default class ClassComp extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {
this.state.count} times (classComp)</p>
<button onClick={
() => this.setState({
count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
État de gestion des composants de fonction (useState)
import React, {
useState } from "react";
export default function FuncComp() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {
count} times (FuncComp)</p>
<button onClick={
() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
3. Détails d'utilisation
(1) État initial différé [Optimisation des performances: initialState calculé par fn, tel que useState (fn)]
Le paramètre initialState ne fonctionnera que dans le rendu initial du composant et sera ignoré dans les rendus suivants. Si l'état initial doit être obtenu par des calculs complexes, vous pouvez transmettre une fonction pour calculer et renvoyer l'état initial dans la fonction. Cette fonction n'est appelée que lors du rendu initial:
- Méthode indésirable 1, initialState sera calculé à chaque rendu, ce qui gaspille les performances.
const initialState = someExpensiveComputation(props);
const [state, setState] = useState(initialState);
- Méthode préférée 2: En passant une fonction, la fonction de calcul de la valeur initiale n'est appelée qu'une seule fois.
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});
(2) Mise à jour fonctionnelle [optimisation du codage: updateState calculé par fn, comme setXxx (fn)]
Si le nouvel état doit être calculé à l'aide de l'état précédent, la fonction peut être transmise à setState. Cette fonction recevra l'état précédent et renverra une valeur mise à jour. L'exemple de composant de compteur suivant montre deux utilisations de setState:
function Counter({
initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<>
Count: {
count}
<button onClick={
() => setCount(initialCount)}>Reset</button>
<button onClick={
() => setCount(prevCount => prevCount - 1)}>-</button>
<button onClick={
() => setCount(prevCount => prevCount + 1)}>+</button>
</>
);
}
(3) Ignorer la mise à jour d'état [Résoudre le doute: si la même mise à jour de valeur est considérée comme un changement d'état]
Lors de l'appel de la fonction de mise à jour de State Hook et de la transmission de l'état actuel, React ignorera le rendu des composants enfants et l'exécution de l'effet . (React utilise l'algorithme de comparaison Object.is pour comparer l'état.)
- object.is algorithme de comparaison comme suit, par ce qui suit peut être initialement conclu que nous pouvons utiliser l'utilisation de base de la règle de jugement d'adresse pour juger.
Object.is('foo', 'foo'); // true
Object.is(window, window); // true
Object.is('foo', 'bar'); // false
Object.is([], []); // false
var foo = {
a: 1 };
var bar = {
a: 1 };
Object.is(foo, foo); // true
Object.is(foo, bar); // false
Object.is(null, null); // true
// 特例
Object.is(0, -0); // false
Object.is(0, +0); // true
Object.is(-0, -0); // true
Object.is(NaN, 0/0); // true
Deux: useEffect
1. Comment utiliser
function useEffect(effect: EffectCallback, deps?: DependencyList): void;
Comme le montre le code source de la définition de hook ci-dessus, le paramètre 1 de la fonction hook useEffect est passé dans une fonction de rappel d'effet secondaire, et le paramètre 2 est passé dans un tableau de dépendances d'effets secondaires (facultatif) , et il n'y a pas de valeur de retour. L'exemple d'utilisation de base est le suivant:
// componentDidMount or componentDidUpdate && count state change
useEffect(() => {
console.log(count)
},[count])
2. Cas d'utilisation
Effets secondaires des composants de classe
import React from "react";
export default class ClassComp extends React.Component {
constructor(props) {
super(props)
this.state = {
count: 0
};
}
componentDidMount() {
console.log('class', 'componentDidMount')
}
componentWillUpdate(nextProps, nextState) {
console.log('class', 'componentWillUpdate')
if(this.state.count !== nextState.count)console.log(this.state.count)
}
componentDidUpdate(prevProps, prevState) {
console.log('class', 'componentDidUpdate')
if(this.state.count !== prevState.count)console.log(this.state.count)
}
componentWillUnmount() {
console.log('class', 'componentWillUnmount')
}
render() {
return (
<div>
<p>You clicked {
this.state.count} times (classComp)</p>
<button onClick={
() => this.setState({
count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
Effets secondaires des composants fonctionnels (useEffect)
import React, {
useState, useEffect } from "react";
export default function FuncComp() {
const [count, setCount] = useState(0)
// 等同于:componentDidMount
useEffect(() => {
console.log('function', 'componentDidMount')
}, [])
// 等同于:componentDidMount or componentDidUpdate
useEffect(() => {
console.log('function', 'componentDidMount or componentDidUpdate')
})
// 等同于:(componentDidMount or componentDidUpdate) && count state change
useEffect(() => {
console.log('function', 'componentDidUpdate console newCount', count)
}, [count])
// 等同于:componentWillUpdate or componentWillUnmount
useEffect(() => {
return () => {
console.log('function', 'componentWillUpdate or componentWillUnmount')
}
})
// 等同于:(componentWillUpdate or componentWillUnmount ) && count state change
useEffect(() => {
return () => {
console.log('function', 'componentWillUpdate or componentWillUnmount console preCount', count)
}
}, [count])
// 等同于:componentWillUnmount
// useEffect(() => {
// return () => {
// console.log('function', 'componentWillUnmount')
// }
// },[])
// 等同于:(componentDidMount or componentDidUpdate) and (componentWillUpdate or componentWillUnmount)
// useEffect(() => {
// console.log('function', 'componentDidMount or componentDidUpdate')
// return () => {
// console.log('function', 'componentWillUpdate or componentWillUnmount')
// }
// })
return (
<div>
<p>You clicked {
count} times (FuncComp)</p>
<button onClick={
() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
résultat de l'opération
- Le montage
peut être vu à partir des résultats en cours d'exécution de ce qui précède. Une fois le composant monté: seule la méthode de cycle de vie componentDidMount du composant de classe est exécutée, et toute la logique d'effets secondaires du composant de fonction est exécutée (il n'y a que trois consoles car les deux derniers useEffects sont uniquement enregistrés Avant la mise à jour et la logique de désinstallation). - La mise à jour
est visible à partir des résultats en cours d'exécution ci-dessus. Une fois le composant mis à jour: les méthodes de cycle de vie componentWillUpdate et componentDidUpdate du composant de classe sont exécutées, et tous les effets secondaires de la logique useEffect du composant de fonction sont tous des effets secondaires, à l'exception du premier tableau de dépendances enregistré qui est vide. La logique est exécutée (il n'y a pas d'effets secondaires selon le tableau également exécuté). - Déchargement
À partir des résultats d'exécution ci-dessus, on peut voir qu'après le déchargement du composant: la méthode de cycle de vie componentWillUnMount du composant de classe est exécutée, et toute la logique d'effet secondaire de useEffect du composant de fonction est exécutée si la logique de désinstallation est enregistrée.
3. Détails d'utilisation
(1) Condition de déclenchement d'utilisation Logique d'effet secondaire d'effet
Par défaut, l'effet sera exécuté après chaque cycle de rendu, mais vous pouvez choisir de le faire exécuter uniquement lorsque certaines valeurs changent en passant le tableau de dépendances.
(2) Le temps d'exécution après le déclenchement de la logique d'effet secondaire useEffect
Contrairement à componentDidMount et componentDidUpdate, une fois que le navigateur a terminé la mise en page et le dessin, la fonction transmise à useEffect sera appelée retardée.
(3) Suppression de la logique des effets secondaires useEffect [pour éviter les fuites de mémoire]
Habituellement, lorsque le composant est désinstallé, il est nécessaire d'effacer les ressources telles que l'abonnement ou l'ID de minuterie créé par l'effet (comme dans le sixième useEffect de l'exemple ci-dessus). Pour éviter les fuites de mémoire, la fonction de nettoyage sera exécutée avant le déchargement du composant.
De plus, si le composant est rendu plusieurs fois (généralement), l'effet précédent sera effacé avant que l'effet suivant ne soit exécuté (comme dans le quatrième / cinquième useEffect dans l'exemple ci-dessus).
4. Encore des doutes
À partir de l'exemple ci-dessus, nous pouvons constater que les hooks useEffect peuvent simuler l'implémentation séparée des deux cycles de vie de willMount et unMount dans le composant de classe, et peuvent également simuler la combinaison de willMount et DidUpdate, la combinaison de unMount et willUpdate, ainsi que willMount et DidUpdate. , UnMount, willUpdate combinaison de quatre. Mais il y a un problème, comment puis-je simuler une méthode de cycle de vie DidUpdate ou WillUpdate distincte? Dans le développement actuel, j'ai rencontré une telle demande. Comme je n'ai pas trouvé de solution appropriée, j'ai épargné l'implémentation de Wanzi, et éliminé l'état de montage en jugeant un certain état du drapeau qui n'est disponible que dans la phase de mise à jour. La logique des effets secondaires n'est exécutée que pendant DidUpdate et non pendant DidMount. S'il y a une meilleure façon de regarder les gens, faites-le moi savoir, merci!