ReactIn16.8Les versions ci - dessus peuvent être utilisées,hooksL'avantage est une meilleure réutilisabilité,C'est réglé.Composants apatrides
Le cycle de vie et la gestion de l'état,Substitutionclass,Peut être personnaliséhookSous la forme d'un composant à grain plus fin divisé,Facile à agrandir et à entretenir.
Hook Pour que tu sois dans le bien et le mal class Peut être utilisé avec plus React Caractéristiques
. Sur le plan conceptuel,React Les composants ont toujours été plus fonctionnels.Et Hook Et embrasser la fonction,Et il n'y a pas de sacrifice. React Principes spirituels.Hook Questions posées Solutions pour,Pas besoin d'apprendre des techniques complexes de programmation fonctionnelle ou réactive.
Regardons un peureactProcessus de rendu global,Pour que tout le monde comprenne mieuxreactProcessus de mise en œuvre,Et ensuitehooksExplication des principes
Sélection dans l'industrie -Ali!ahooksBibliothèque
ReactPiliers de l'optimisation des performances——ImmutableFlux de données
useState
EtuseReducer
En coursEnvoyer des mises à jour
(Rendre les composants de la fonction).
useRef
Mise en cache des variables et modification des variables non effectuéeEnvoyer des mises à jour
,ref.current
Obtenir les variables mises en cache
useEffect
Les effets indésirables peuvent être mis à jour ,IndomDéclenche une fonction de rappel après le montage sur la page pour le rendu,Comme une demande de réseau,Temps de mise à jour, etc..
useLayoutEffect
CréationdomAprès,Montagedom Appelé avant la page ,Vous pouvez effectuer des opérations indépendantes du rendu, Comme publier des abonnements, etc.
useCallback
Peut mettre en cache des fonctions ,QuandEnvoyer des mises à jour
Heure,Les paramètres dépendants ne changent pas, Ne pas créer Nouvelles fonctions
,useCallback(fn, deps)
équivalent à useMemo(() => fn, deps)
.
useMemo
Peut mettre en cache l'état , Optimiser les performances
useContext
DisponibleReact.createContext Objet contextuel créé
const Context = createContext(null);
function Parent () {
return (<Context.Provider value={{ a: 1 }}> <Child /> </Context.Provider>);
}
function Child () {
const data = useContext(Context)
console.log(data);
return null;
}
export default Parent;
Copier le Code
useImperativeHandle
CoopérationforwardRef
Les paramètres du sous - composant peuvent être transmis à travers le composant parent,Composant parent viaref.current Obtenir les paramètres entrants
// UtiliserforwardRef, Le deuxième paramètre sera reçu , Pour transmission directe refOu en combinaison avecuseImperativeHandle Lier les données des sous - composants
function SetStatePage(props, ref) {
const [count ,setCount] = useState(0)
// Le premier paramètre reçoit la transmission ref, Second Parameter receiver function , Renvoie les données à transmettre
useImperativeHandle(ref, () => ({
count,
setCount
}))
return (
<div> <p>You clicked {count} times</p> </div>
)
}
// forwardRefTransmissibleref
const SetStatePageWithRef = forwardRef(SetStatePage);
function Parent () {
const ref = useRef(null);
return (<div> <SetStatePageWithRef ref={ref} /> {/* Adoptionref.current Obtenir des données pour les sous - composants */} <button onClick={() => ref.current.setCount(ref.current.count + 1)}>Click me</button> </div>);
}
export default Parent;
Copier le Code
useDebugValue
Disponible en React Affichage dans les outils de développement Personnalisation hook
Étiquette de( Doit être personnalisé HookUtilisé dans),Comme en bas.,Il peut également recevoir un second paramètre,Fonction de rappel pour le chargement différé,Réceptiondebug Valeur comme argument , Retour traité debug Afficher les valeurs
export default function SetStatePage(props) {
function useOnline (state) {
const [isOnline, setIsOnline] = useState(state);
useDebugValue(isOnline > 5 ? 'Online' : 'Offline', (debug) => {
if (debug === 'Online') {
return true;
} else {
return false;
}
});
return [isOnline, setIsOnline];
}
function useFriendStatus(friendID) {
const [id, setID] = useState(friendID);
// Celui - ci dans les outils de développement Hook Afficher les étiquettes à côté
// "FriendStatus: Online"
useDebugValue(id > 5 ? 'Online' : 'Offline');
return [id, setID];
}
const [id, setID] = useFriendStatus(3);
const [isOnline, setIsOnline] = useOnline(3);
return (
<div> <p>You clicked {isOnline} times</p> <button onClick={() => setID(id + 1)}>Click ID</button> <button onClick={() => setIsOnline(isOnline + 1)}>Click Online</button> </div>
)
}
Copier le Code
Comme au - dessus.useDebugValueNous pouvons utiliser Google explorerReact devtoolsPlug - in
Vous pouvez voir lehooksStatut
,Comment cet état a - t - il été obtenu?On pourrait étudier sa réalisation, Et trouver la réponse
InReactMoyenne,Chaque exécutionuseStateOuuseReducer Toutes les fonctions de mise à jour sont déclenchées Envoyer des mises à jour
,Exécuter à nouveau les composants de la fonction pour rendre à nouveau, Si vous ne mettez pas en cache hooksÉtat de,N'est - ce pas la même valeur chaque fois que vous obtenez un état
Comment mettre en cache hooksÉtat de, Où est le cache? ? La réponse est:react16
fiberArchitecture
Moyenne
react Dans la grande version 16Quand,Virtualiserdom La structure de l'arbre est convertie en Liste des liensfiber
,Adoptionchild、sibling、return
Pointer vers un autre noeud ,L'avantage est que Je peux vous interrompre.
EtParamètresdom Priorités opérationnelles
Nouveau et anciendomComparer,diff Processus de fragmentation , Similaire à la structure de données suivante
{
type: Marquer le type de noeud (dom Chaîne d 'étiquettes ,Fonctions,Catégorie),
key: Valeur unique au niveau actuel du noeud,
props: Propriétés,
stateNode: Primitivedom、Exemple de classe,
child: Sous - noeud,
return: Noeud parent,
sibling: Noeud frère,
alternate: Vieux noeud,
flags: Instructions de fonctionnement(Ajouter,Remplacer,Mise à jour),
deletions: Pour supprimer un noeud enfant nullOu[],
index: Indice au niveau actuel ,De0C'est parti.
memorizedState: hookNoeud d'en - tête de la liste de liens
}
Copier le Code
hooks En fait, tout est là. fiber.memorizedState
Là - haut, Voilà la réponse. React devtoolsPlug - in
Comment obtenir le statut ,PourquoimemorizedState
Pourquoi une structure de liste liée au lieu d'un tableau, Je pense que c'est un besoin Discontinu
Espace de stockage pour
Pourquoi ne peut - on appeler que la couche externe de la fonction Hook? Pourquoi pas en boucle? 、Jugement conditionnel ou appel dans une sous - fonction
Pour répondre aux questions ci - dessus ,Pour comprendrereact hooks
Principe de réalisation,On a raison.Fiber Liste de liens dfsHeure,Je vais juger.typePropriétés, Si une fonction ,Il passera.type(props)
Exécuter la fonction,Obtenir un nouveauFiber,reconcileChildren
Nouveau et ancien noeud diff,Voici une simplification de la mise en œuvre du code source,Facile à comprendre:
// Composant de fonction
export function updateFunctionComponent(wip) {
renderWithHooks(wip);
const {type, props} = wip;
const newFiber = type(props);
// Sous - noeud de coordination
reconcileChildren(wip, newFiber);
}
Copier le Code
Avant d'exécuter un composant de fonction,Sera appelé en premierrenderWithHooks
La fonction passe dansFiber, Variables globales currentlyRenderingFiber
Assigner une valeur, Pour le suivi hooks API
Appel de
function renderWithHooks(fiber) {
currentlyRenderingFiber = fiber;
currentlyRenderingFiber.memoizedState = null;
// Dans le code source est un updateQueue Tableau à stocker , C'est simple. , Écrivez séparément useEffectEtuseLayoutEffect
currentlyRenderingFiber.updateQueueOfEffect = [];
currentlyRenderingFiber.updateQueueOfLayout = [];
workInProgressHook = null;
}
Copier le Code
AdoptionFiber.alternate
( Pour l'ancien Fiber)Pour déterminer s'il s'agit d'un rendu initial
Via les variables globales currentlyRenderingFiber
Travaux en cours Fiber,workInProgressHook
En coursHook,currentHook
Travaux en cours hook Ancien correspondant hook,Pour obtenir En cours hook
Et extraction hookDépendances
En coursComparaison superficielle
unction updateWorkInProgressHook() {
let hook = null;
// todo get hook
// Vieux noeud
let current = currentlyRenderingFiber.alternate;
if (current) {
// Phase de mise à jour NouveauhookDans le vieuxhook Mise à jour sur la base
currentlyRenderingFiber.memoizedState = current.memoizedState;
if (workInProgressHook) {
// Non.0- Oui.hook
hook = workInProgressHook = workInProgressHook.next;
currentHook = currentHook.next;
} else {
// Oui.0- Oui.hook
hook = workInProgressHook = current.memoizedState;
currentHook = current.memoizedState;
}
} else {
// Première phase de rendu
currentHook = null;
hook = {
memoizedState: null, // Valeur du Statut
next: null, // Suivant.hook
};
if (workInProgressHook) {
// Non.0- Oui.hook
workInProgressHook = workInProgressHook.next = hook;
} else {
// Oui.0- Oui.hook
workInProgressHook = currentlyRenderingFiber.memoizedState = hook;
}
}
return hook;
}
Copier le Code
updateWorkInProgressHook
Obtenir l'exécution actuelle hookcurrentlyRenderingFiber
Déterminer si ce n'est pas le premier rendunewState
Pour mettre à jourhook État et envoi des mises à jour function useState (state) {
const hook = updateWorkInProgressHook();
if (!currentlyRenderingFiber.alternate) {
// Rendu initial
hook.memoizedState = state;
}
const dispatch = (newState) => {
hook.memoizedState = newState;
scheduleUpdateOnFiber(currentlyRenderingFiber);
};
return [hook.memoizedState, dispatch];
}
Copier le Code
currentHook
Une comparaison superficielle entre les dépendances antérieures sauvegardées et les dépendances existantesupdateQueue
La fonction de rappel est exécutée de façon synchrone ou asynchroneexport function useEffect(create, deps) {
return updateEffectIml(HookPassive, create, deps);
}
export function useLayoutEffect(create, deps) {
return updateEffectIml(HookLayout, create, deps);
}
export function updateEffectIml(hookFlag, create, deps) {
const hook = updateWorkInProgressHook();
const effect = {hookFlag, create, deps};
// Lors de la mise à jour des composants ,Et la dépendance n'a pas changé
if (currentHook) {
const prevEffect = currentHook.memoizedState;
if (deps) {
const prevDeps = prevEffect.deps;
if (areHookInputsEqual(deps, prevDeps)) {
return;
}
}
}
hook.memoizedState = effect;
if (hookFlag & HookPassive) {
currentlyRenderingFiber.updateQueueOfEffect.push(effect);
} else if (hookFlag & HookLayout) {
currentlyRenderingFiber.updateQueueOfLayout.push(effect);
}
}
Copier le Code
QuandFiberNoeuddiffUne fois terminé,commitSoumettredom Lors du montage ,useLayoutEffectRappelExécution immédiate
,useEffectLa fonction passe parscheduleCallback Programmation asynchrone ,Il sera là.domAprès le rendu
Mise en œuvre