- Κατανοήστε πώς το useState διατηρεί και ενημερώνει την κατάσταση των τοπικών στοιχείων, συμπεριλαμβανομένων των λειτουργικών ενημερώσεων και του χειρισμού αντικειμένων.
- Χρησιμοποιήστε το useEffect για παρενέργειες με σαφή λογική εγκατάστασης/καθαρισμού και ακριβείς πίνακες εξαρτήσεων για να αποφύγετε διαρροές και βρόχους.
- Συνδυάστε τις συναρτήσεις useState και useEffect για πραγματικές εργασίες, όπως ανάκτηση δεδομένων, συνδρομές και ενημερώσεις DOM σε στοιχεία συναρτήσεων.
- Ακολουθήστε τους κανόνες των hooks και αντιμετωπίστε τα εφέ ως διεργασίες "μετά την απόδοση" για να διατηρήσετε τα στοιχεία του React προβλέψιμα και συντηρήσιμα.
Τα React hooks άλλαξαν εντελώς τον τρόπο που γράφουμε components, και mastering useState useEffect είναι ουσιαστικά το εισιτήριο εισόδου στη συγγραφή σύγχρονου κώδικα React. Εάν τα χρησιμοποιείτε ήδη αλλά εξακολουθείτε να κολλάτε με άπειρους βρόχους, παλιά κατάσταση ή περίπλοκους πίνακες εξαρτήσεων, αυτός ο οδηγός θα σας βοηθήσει να συνδέσετε όλα τα κομμάτια που λείπουν με έναν πρακτικό τρόπο.
Σε αυτό το άρθρο θα αναλύσουμε λεπτομερώς πώς να το χρησιμοποιήσουμε σωστά useState useEffect μαζι, γιατί εισήχθησαν εξαρχής τα hooks, οι επίσημοι κανόνες και οι προειδοποιήσεις, πώς λειτουργούν πραγματικά οι εξαρτήσεις στο παρασκήνιο, συνήθεις παγίδες που καταστρέφουν τα στοιχεία σας και δοκιμασμένα μοτίβα για παρενέργειες, καθαρισμό και διαχείριση κατάστασης σε πραγματικά έργα.
Γιατί hooks, και γιατί συγκεκριμένα useState και useEffect;
Προστέθηκαν άγκιστρα στο React 16.8 για να επιτρέψουν στα στοιχεία συνάρτησης να χρησιμοποιούν χαρακτηριστικά κατάστασης και κύκλου ζωής χωρίς κλάσεις.Πριν από αυτό, έπρεπε να γράφετε στοιχεία κλάσης για να διατηρείτε την τοπική κατάσταση, να εγγράφεστε σε εξωτερικά δεδομένα ή να αντιδράτε σε συμβάντα κύκλου ζωής όπως η προσάρτηση και η αποπροσάρτηση.
Το μεγάλο πρόβλημα με τις κλάσεις ήταν ότι η σχετική λογική συχνά χωριζόταν σε πολλαπλές μεθόδους κύκλου ζωής. όπως το πορτοκαλί και το κίτρινο μπορούν να φωτίσουν τα έπιπλά σας και να τα αναδείξουν. Αυτά τα χρώματα ταιριάζουν καλά με ξύλα ανοιχτών τόνων, προσθέτοντας ζεστασιά και ζωντάνια στον χώρο. componentDidMount, componentDidUpdate componentWillUnmountΘα καταλήξετε με κομμάτια του ίδιου χαρακτηριστικού διάσπαρτα σε διαφορετικές μεθόδους με βάση πότε τρέχουν αντί για τι το κάνουν, γεγονός που καθιστά τον κώδικα πιο δύσκολο στην ανάγνωση, τη δοκιμή και την επαναχρησιμοποίηση.
Οι γάντζοι αναστρέφουν αυτό το μοντέλο: με useState συνδέετε κατάσταση απευθείας σε ένα στοιχείο συνάρτησης και με useEffect Συνδέετε τις παρενέργειες απευθείας με τη λογική που τις χρειάζεται. Με αυτόν τον τρόπο, μπορείτε να ομαδοποιήσετε όλα όσα σχετίζονται με ένα μόνο ζήτημα σε ένα μέρος και να εξαγάγετε εύκολα επαναχρησιμοποιήσιμα άγκιστρα αργότερα.
Ανάμεσα σε όλα τα άγκιστρα, useState useEffect είναι τα βασικά πρωτόγοναΜπορείτε να δημιουργήσετε τις περισσότερες καθημερινές λειτουργίες μόνο με αυτά τα δύο: φόρμες και εναλλαγές όπως καταστάσεις UI, αιτήματα δικτύου, συνδρομές, χρονοδιακόπτες, ενημερώσεις DOM και πολλά άλλα. Άλλα hooks (useRef, useReducer, useContext, useMemo...) είναι υπέροχα, αλλά βασίζονται στις ίδιες ιδέες.
Κανόνες των React hooks που δεν πρέπει ποτέ να παραβιάσετε
Τα React hooks συνοδεύονται από μερικούς αυστηρούς κανόνες που τα καθιστούν αξιόπιστα σε όλες τις renders.Εάν τα παραβιάσετε, θα δείτε είτε σφάλματα χρόνου εκτέλεσης είτε πολύ ανεπαίσθητα, δύσκολα στην αντιμετώπιση σφαλμάτων.
Πρώτος κανόνας: καλέστε hooks μόνο μέσα σε στοιχεία συνάρτησης React ή προσαρμοσμένα hooksΔεν μπορείτε να χρησιμοποιήσετε useState or useEffect σε στοιχεία κλάσης, κανονικές συναρτήσεις χρησιμότητας ή εκτός οποιουδήποτε στοιχείου. Ένα μοτίβο όπως αυτό δεν είναι έγκυρο:
import React, { Component, useState } from 'react';
class App extends Component {
// ❌ This will throw - hooks don’t work in classes
const = useState(0);
render() {
return <h1>Hello, I am a Class Component!</h1>;
}
}
Η σωστή προσέγγιση είναι να μετακινηθείτε σε ένα στοιχείο συνάρτησης εάν θέλετε να χρησιμοποιήσετε άγκιστρα:
import React, { useState } from 'react';
function App() {
const = useState('');
return (
<div>
Your JSX code goes in here...
</div>
);
}
export default App;
Δεύτερος κανόνας: καλέστε μόνο hooks στο ανώτατο επίπεδο του component σαςΑυτό σημαίνει ότι δεν υπάρχουν άγκιστρα μέσα σε βρόχους, συνθήκες ή ένθετες συναρτήσεις. Το React βασίζεται στην κλήση των άγκιστρων με την ίδια σειρά σε κάθε απόδοση για να «ταιριάξει» κάθε ένα. useState useEffect κλήση με τα αποθηκευμένα δεδομένα της, επομένως αυτό δεν είναι έγκυρο:
function BadComponent({ enabled }) {
if (enabled) {
// ❌ Wrong: hook inside a conditional
const = useState(0);
}
// ...
}
Αντ' αυτού, δηλώστε τα hooks άνευ όρων στην κορυφή και χρησιμοποιήστε υποθετικούς όρους μέσα στο εφέ ή στο JSX.Το άγκιστρο πρέπει πάντα να καλείται, αλλά η λογική που εκτελεί μπορεί να είναι υπό όρους:
function ConditionalEffectComponent() {
const = useState(false);
useEffect(() => {
if (isMounted) {
console.log('Component mounted');
}
}, );
return (
<div>
<button onClick={() => setIsMounted(!isMounted)}>
{isMounted ? 'Unmount' : 'Mount'}
</button>
</div>
);
}
Ο τρίτος σιωπηρός κανόνας είναι ότι τα hooks πρέπει να εισάγονται από το React (ή μια βιβλιοθήκη hook) και όχι να εφαρμόζονται ad‑hoc.Αυτό είναι προφανές, αλλά αξίζει να το πούμε: η μαγεία βρίσκεται στον εσωτερικό αποστολέα hook του React που παρακολουθεί τις κλήσεις hook σε όλες τις renders.
Σωστή διαχείριση τοπικής κατάστασης με το useState
useState σας επιτρέπει να συνδέσετε κατάσταση σε ένα στοιχείο συνάρτησης και να λάβετε τόσο την τρέχουσα τιμή όσο και μια συνάρτηση ενημέρωσηςΕννοιολογικά είναι το λειτουργικό αντίστοιχο του this.state this.setState σε στοιχεία κλάσης.
Ένα ελάχιστο αντίστροφο παράδειγμα με useState μοιάζει με αυτό:
import React, { useState } from 'react';
function Counter() {
const = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default Counter;
Όταν καλείτε useState(initialValue), Το React αποθηκεύει αυτό που αναφέρει και επιστρέφει ένα ζεύγος: η τρέχουσα τιμή κατάστασης και ένας οριστής. Σε αντίθεση με τις κανονικές τοπικές μεταβλητές, η κατάσταση επιβιώνει σε όλες τις αποδόσεις, επομένως η count Η τιμή δεν επαναφέρεται στο 0 κάθε φορά που εκτελείται η συνάρτηση component.
Μπορείτε να χρησιμοποιήσετε οποιαδήποτε σειριοποιήσιμη τιμή για την κατάσταση: αριθμούς, συμβολοσειρές, λογικές τιμές, πίνακες, αντικείμενα, ακόμη και συναρτήσεις.Μπορείτε επίσης να καλέσετε useState πολλές φορές στο ίδιο στοιχείο για να διατηρήσετε τις σχετικές τιμές ξεχωριστές αντί να τοποθετείτε τα πάντα σε ένα μόνο αντικείμενο.
Όταν η νέα τιμή κατάστασης εξαρτάται από την προηγούμενη, χρησιμοποιείτε πάντα τη φόρμα ενημέρωσης συναρτήσεωνΑυτό αποφεύγει σφάλματα όταν συμβαίνουν πολλαπλές ενημερώσεις κατάστασης σε γρήγορη διαδοχή:
setCount(prev => prev + 1);
Μια άλλη λεπτή αλλά σημαντική λεπτομέρεια είναι ότι η κλήση του setter αντικαθιστά ολόκληρη την τιμή κατάστασης, δεν συγχωνεύει αντικείμενα όπως this.setState σε τάξειςΕάν η κατάστασή σας είναι ένα αντικείμενο ή ένας πίνακας, πρέπει να διαδώσετε μόνοι σας την προηγούμενη τιμή:
const = useState({ name: 'Alex', age: 30 });
// ✅ Correct: copy and update
setUser(prev => ({ ...prev, age: prev.age + 1 }));
Για ακριβές αρχικές τιμές, μπορείτε να αρχικοποιήσετε την κατάσταση με αργό ρυθμό περνώντας μια συνάρτηση σε useStateΤο React θα το καλέσει μόνο στην πρώτη απόδοση:
const = useState(() => calculateInitialValue());
Αντιμετώπιση παρενεργειών με χρήσηΕπίδραση
useEffect είναι το API του React για την εκτέλεση παρενεργειών σε στοιχεία συνάρτησηςΜια «παρενέργεια» είναι οτιδήποτε αγγίζει τον έξω κόσμο: ανάκτηση δεδομένων, καταγραφή, άμεσες αλλαγές DOM, συνδρομές, χρονοδιακόπτες, API προγράμματος περιήγησης κ.λπ.
Εννοιολογικά, useEffect αντικαθιστά έναν συνδυασμό componentDidMount, componentDidUpdate componentWillUnmount από τα στοιχεία της κλάσηςΑντί να διαιρείτε ένα εφέ σε τρεις μεθόδους κύκλου ζωής, το δηλώνετε μία φορά και αφήνετε το React να το χειρίζεται πότε εκτελείται και πότε καθαρίζεται.
Η βασική υπογραφή είναι useEffect(setup, dependencies?). ο setup Η συνάρτηση είναι το σώμα του εφέ σας. Μπορεί προαιρετικά να επιστρέψει μια συνάρτηση καθαρισμού. dependencies Ο πίνακας ενημερώνει το React πότε το εφέ χρειάζεται να εκτελεστεί ξανά.
useEffect(() => {
// side effect logic here
return () => {
// optional cleanup logic here
};
}, );
Από προεπιλογή, χωρίς το δεύτερο όρισμα, το εφέ θα εκτελείται μετά από κάθε απόδοση (πρώτη προσάρτηση και κάθε επόμενη ενημέρωση). Αυτό είναι συχνά υπερβολικό για αιτήματα δικτύου ή ακριβή λογική.
Ένα πολύ συνηθισμένο μοτίβο είναι να ενημερώνεται κάτι εξωτερικό κάθε φορά που αλλάζει η κατάσταση ενός τμήματος.Για παράδειγμα, ενημέρωση του τίτλου σελίδας ανάλογα με τον αριθμό των κλικ:
import React, { useState, useEffect } from 'react';
function Counter() {
const = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, ); // effect re-runs only when `count` changes
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
Ο πίνακας εξάρτησης είναι κρίσιμος για την απόδοση και την ορθότηταΕλέγχει πότε το React θα πρέπει να εκτελέσει ξανά το εφέ: εάν κάποια εξάρτηση έχει αλλάξει σύμφωνα με Object.is Συγκριτικά, το εφέ καθαρίζεται και εκτελείται ξανά. Εάν δεν αλλάξει τίποτα, παραλείπεται.
Κατανόηση του πίνακα εξαρτήσεων σαν επαγγελματίας
Ο πίνακας εξάρτησης είναι το πιο ανεπαίσθητο σημείο useEffect τα έντομα προέρχονται απόΤο React συγκρίνει κάθε στοιχείο του πίνακα με την προηγούμενη τιμή του χρησιμοποιώντας Object.isΕάν όλες οι τιμές είναι ίσες, το εφέ παραλείπεται. Εάν τουλάχιστον μία είναι διαφορετική, το εφέ εκτελείται ξανά.
Υπάρχουν τρεις κύριες διαμορφώσεις εξαρτήσεων που θα χρησιμοποιείτε συνεχώς:
- Δεν υπάρχει δεύτερο επιχείρημα: το εφέ εκτελείται μετά από κάθε απόδοση.
- Κενός πίνακας
[]: το εφέ εκτελείται μόνο μία φορά κατά την προσάρτηση και καθαρίζεται κατά την αποπροσάρτηση. - Πίνακας με τιμές
: το εφέ εκτελείται μετά την προσάρτηση και κάθε φορά που αλλάζει οποιαδήποτε εξάρτηση.
Όταν οι εξαρτήσεις είναι πρωτόγονες τιμές (αριθμοί, συμβολοσειρές, λογικές τιμές), αυτό είναι απλό.Τα προβλήματα ξεκινούν όταν τοποθετείτε αντικείμενα, πίνακες ή συναρτήσεις μέσα στις εξαρτήσεις, επειδή η ισότητα βασίζεται σε αναφορές. Δύο πανομοιότυπα αντικείμενα με διαφορετικές αναφορές θεωρούνται «διαφορετικά», γεγονός που προκαλεί επανεκτελέσεις σε κάθε απόδοση.
Θεωρήστε ένα φαινόμενο που εξαρτάται από ένα team αντικείμενο από στηρίγματα:
function Team({ team }) {
useEffect(() => {
console.log(team.id, team.active);
}, ); // ⚠️ might re-run every render if `team` reference changes
}
Ακόμα κι αν το πραγματικό περιεχόμενο της ομάδας δεν αλλάξει, μια νέα αναφορά αντικειμένου σε κάθε απόδοση θα αναγκάσει το εφέ να εκτελεστεί ξανά.Για να το αποφύγετε αυτό, είτε βασιστείτε στα πρωτόγονα πεδία που χρησιμοποιείτε στην πραγματικότητα είτε ανακατασκευάστε το αντικείμενο μέσα στο ίδιο το εφέ.
Μια ασφαλέστερη έκδοση παρακολουθεί μόνο ό,τι πραγματικά χρειάζεται το αποτέλεσμα:
function Team({ team }) {
const { id, active } = team;
useEffect(() => {
console.log(id, active);
}, );
}
Αν πραγματικά χρειάζεστε ολόκληρο το αντικείμενο μέσα στο εφέ, μπορείτε να το αναδημιουργήσετε εκεί αντί να το χρησιμοποιήσετε ως εξάρτηση.Με αυτόν τον τρόπο, η λίστα εξαρτήσεων μπορεί να εξακολουθεί να βασίζεται σε πρωτόγονα:
function Team({ team }) {
const { id, active, name } = team;
useEffect(() => {
const localTeam = { id, active, name };
// use `localTeam` here
}, );
}
Ως έσχατη λύση, μπορείτε να χρησιμοποιήσετε την απομνημόνευση με useMemo or useCallback για ακριβά αντικείμενα ή λειτουργίες, αλλά να θυμάστε ότι η ίδια η απομνημόνευση έχει ένα κόστος. Μην την σκορπίζετε παντού «για κάθε ενδεχόμενο». Προσθέστε την όταν μια συγκεκριμένη εξάρτηση προκαλεί πραγματικά προβλήματα απόδοσης.
Καθαρισμός των εφέ σωστά
Ορισμένες παρενέργειες κατανέμουν πόρους που πρέπει να απελευθερωθούν: συνδρομές, υποδοχές, διαστήματα, χρονικά όρια, ακροατές συμβάντων, κ.λπ. Η παράλειψη του καθαρισμού τους μπορεί εύκολα να οδηγήσει σε διαρροές μνήμης ή διπλή εργασία.
In useEffect, ο καθαρισμός γίνεται επιστρέφοντας μια συνάρτηση από το εφέΤο React θα καλέσει αυτήν τη συνάρτηση πριν εκτελέσει ξανά το εφέ με νέες εξαρτήσεις, καθώς και για μια τελευταία φορά όταν το στοιχείο αποσυνδεθεί.
import { useEffect } from 'react';
function LogMessage({ message }) {
useEffect(() => {
const log = setInterval(() => {
console.log(message);
}, 1000);
return () => {
clearInterval(log);
};
}, );
return <div>logging to console "{message}"</div>;
}
Σε αυτό το παράδειγμα, κάθε φορά message αλλαγές, το React πρώτα διαγράφει το παλιό διάστημα και στη συνέχεια δημιουργεί ένα νέο με το ενημερωμένο μήνυμαΌταν το στοιχείο εξαφανιστεί από το περιβάλλον χρήστη, η τελευταία εκκαθάριση διαγράφει οριστικά το διάστημα.
Αυτός ο συνδυασμός «ρύθμιση + καθαρισμός» είναι κεντρικός στο νοητικό μοντέλο του useEffectΠροσπαθήστε να σκεφτείτε κάθε εφέ ως μια αυτόνομη διαδικασία που ξεκινά στη συνάρτηση εγκατάστασης και σταματά εντελώς στη συνάρτηση καθαρισμού. Το React μπορεί να εκτελέσει πολλαπλούς κύκλους εγκατάστασης/καθαρισμού κατά την ανάπτυξη (ειδικά σε λειτουργία Strict) για να ελέγξει αν ο καθαρισμός σας πραγματικά αναιρεί τα πάντα.
Ένα κλασικό παράδειγμα είναι η εγγραφή σε μια εξωτερική πηγή, όπως ένα API συνομιλίας ή ένα συμβάν προγράμματος περιήγησης (βλ. χειρισμός του onKeyDown στο React):
useEffect(() => {
function handleClick(event) {
console.log('Clicked', event.clientX, event.clientY);
}
document.addEventListener('click', handleClick);
return () => {
document.removeEventListener('click', handleClick);
};
}, []); // runs once on mount, cleans up on unmount
Χρήση των useState και useEffect μαζί για την ανάκτηση δεδομένων
Ένας από τους πιο συνηθισμένους συνδυασμούς στον πραγματικό κόσμο είναι η χρήση useState useEffect για να ανακτήσετε δεδομένα από ένα APIΔιατηρείτε τα δεδομένα (και ίσως τις σημαίες φόρτωσης/σφάλματος) στην κατάσταση και εκτελείτε το αίτημα σε ένα εφέ που εκτελείται όταν το στοιχείο προσαρτάται ή όταν αλλάζει κάποια παράμετρος.
Ένα βασικό μοτίβο για την ανάκτηση δεδομένων κατά την προσάρτηση μοιάζει με αυτό:
import { useEffect, useState } from 'react';
function FetchItems() {
const = useState([]);
useEffect(() => {
let ignore = false;
async function fetchItems() {
try {
const response = await fetch('/items');
const fetchedItems = await response.json();
if (!ignore) {
setItems(fetchedItems);
}
} catch (error) {
console.error('Error fetching items:', error);
}
}
fetchItems();
return () => {
// avoid updating state if the component unmounted
ignore = true;
};
}, []);
return (
<div>
{items.map(item => (
<div key={item.id ?? item}>{item.name ?? item}</div>
))}
</div>
);
}
Εδώ, ο κενός πίνακας εξάρτησης διασφαλίζει ότι το αίτημα εκτελείται ακριβώς μία φορά. Το εσωτερικό ignore Η σημαία είναι ένας απλός τρόπος για να αποφύγετε τον ορισμό κατάστασης σε ένα μη προσαρτημένο στοιχείο σε περίπτωση που το αίτημα επιλυθεί αργά.
Είναι επίσης πολύ συνηθισμένο να προσθέτετε μια σημαία φόρτωσης και να εμφανίζετε έναν περιστρεφόμενο διακόπτη ή ένα σύμβολο κράτησης θέσης ενώ τα δεδομένα βρίσκονται καθ' οδόν.:
const Statistics = () => {
const = useState([]);
const = useState(true);
useEffect(() => {
const getStats = async () => {
try {
const statsData = await getData();
setStats(statsData);
} finally {
setLoading(false);
}
};
getStats();
}, []);
if (loading) {
return <div>Loading statistics...</div>;
}
return (
<ul>
{stats.map(stat => (
<li key={stat.id}>{stat.label}: {stat.value}</li>
))}
</ul>
);
};
Εάν το ερώτημά σας εξαρτάται από μια παράμετρο (όπως μια κατηγορία, ένα φίλτρο ή μια παράμετρο δρομολόγησης), προσθέστε αυτήν την παράμετρο στον πίνακα εξάρτησης έτσι ώστε το εφέ να επαναλαμβάνεται όταν αλλάζει:
useEffect(() => {
async function fetchItems() {
const response = await fetch(`/items?category=${category}`);
const data = await response.json();
setItems(data);
}
fetchItems();
}, );
Σκέψη με βάση τα «εφέ σε κάθε render» έναντι των «κύκλων ζωής»
Αν είστε συνηθισμένοι στα στοιχεία της κλάσης, μπορεί να είναι δελεαστικό να χαρτογραφήσετε νοερά useEffect για να προσαρτήσετε/ενημερώσετε/αποπροσαρτήσετε μεθόδους, αλλά αυτό συνήθως οδηγεί σε μεγαλύτερη σύγχυση. Ένα απλούστερο νοητικό μοντέλο είναι: «τα εφέ εκτελούνται μετά τις αποδόσεις και ενδέχεται να καθαριστούν πριν από την επόμενη εκτέλεση».
Στα μαθήματα, συχνά έπρεπε να αντιγράφεις τη λογική μεταξύ componentDidMount componentDidUpdate επειδή θέλατε το ίδιο εφέ να εκτελείται τόσο κατά την προσάρτηση όσο και κατά τις ενημερώσεις. Με τα hooks, αυτή η επικάλυψη εξαφανίζεται: ένα μόνο εφέ καλύπτει και τις δύο περιπτώσεις και το React φροντίζει για τον καθαρισμό μεταξύ των εκτελέσεων.
Αυτός ο σχεδιασμός εξαλείφει επίσης μια ολόκληρη κατηγορία σφαλμάτων που σχετίζονται με τον μη σωστό χειρισμό των ενημερώσεων.Για παράδειγμα, σε ένα στοιχείο κλάσης που εγγράφεται στην κατάσταση σύνδεσης ενός φίλου, είναι εύκολο να ξεχάσετε να εγγραφείτε ξανά όταν props.friend αλλαγές, προκαλώντας παλιές συνδρομές ή σφάλματα κατά την αποσύνδεση. Με useEffect που απαριθμεί friend.id Ως εξάρτηση, το React θα εκτελέσει αυτόματα τον καθαρισμό για τον παλιό φίλο και την εγκατάσταση για τον νέο.
Λάβετε υπόψη ότι κατά την ανάπτυξη της Strict Mode, το React εκτελεί σκόπιμα τον κύκλο εγκατάστασης + καθαρισμού δύο φορές κατά την προσάρτηση.Αυτό δεν συμβαίνει στην παραγωγή, αλλά είναι ένα χρήσιμο stress test για να επιβεβαιώσετε ότι ο καθαρισμός σας αναιρεί πραγματικά τα πάντα και ότι το εφέ σας μπορεί να εκτελεστεί με ασφάλεια πολλές φορές.
Βελτιστοποίηση και αντιμετώπιση προβλημάτων συμπεριφοράς useEffect
Όταν ένα εφέ εκτελείται συχνότερα από το αναμενόμενο, το πρώτο πράγμα που πρέπει να ελέγξετε είναι ο πίνακας εξάρτησηςΕίτε μια εξάρτηση αλλάζει σε κάθε απόδοση (κοινό με τα ενσωματωμένα αντικείμενα/συναρτήσεις) είτε ξεχάσατε να καθορίσετε καθόλου τον πίνακα.
Η καταγραφή των τιμών εξάρτησης είναι ένας γρήγορος τρόπος για τον εντοπισμό σφαλμάτων:
useEffect(() => {
console.log('Effect deps:', dep1, dep2);
}, );
Εάν βλέπετε διαφορετικά αρχεία καταγραφής κάθε φορά, ελέγξτε ποια εξάρτηση αλλάζει στην πραγματικότητα.Συχνά θα βρείτε ένα ενσωματωμένο αντικείμενο ή μια συνάρτηση βέλους που αναδημιουργείται σε κάθε απόδοση. Μετακίνηση της δημιουργίας αντικειμένου μέσα στο εφέ ή ανύψωση συναρτήσεων εκτός του στοιχείου ή απομνημόνευσή τους με useCallback μπορεί να σταθεροποιήσει τις εξαρτήσεις όταν χρειάζεται.
Άπειροι βρόχοι συμβαίνουν όταν ένα εφέ εξαρτάται από μια τιμή και ενημερώνει άνευ όρων την ίδια τιμή.. Για παράδειγμα:
useEffect(() => {
setCount(count + 1); // ⚠️ will cause a loop if `count` is a dependency
}, );
Κάθε φορά count αλλαγές, το εφέ εκτελείται, ενημερώσεις count ξανά, ενεργοποιεί μια άλλη απόδοση, και ούτω καθεξήςΓια να σπάσετε αυτό το μοτίβο, σκεφτείτε αν η ενημέρωση κατάστασης ανήκει πραγματικά σε ένα εφέ, αν θα πρέπει να ενεργοποιηθεί από μια αλληλεπίδραση χρήστη ή αν μπορείτε να βασιστείτε σε μια διαφορετική τιμή.
Μερικές φορές θέλετε να διαβάσετε την τελευταία τιμή κάποιας κατάστασης ή props μέσα σε ένα εφέ χωρίς αυτή η τιμή να ενεργοποιήσει μια επανάληψη.Σε αυτά τα προηγμένα σενάρια, νεότερα API όπως τα "effect events" (μέσω useEffectEvent στα έγγραφα του React) ή οι αναφορές μπορούν να βοηθήσουν, αλλά για τις περισσότερες πρακτικές περιπτώσεις, η παραμονή πιστή στις εξαρτήσεις είναι ασφαλέστερη και απλούστερη.
Συνδυάζοντας τα πάντα, χρησιμοποιώντας useState useEffect σωστά καταλήγει σε μερικές βασικές συνήθειεςΔιατηρήστε την κατάσταση μικρή και εστιασμένη, προτιμήστε τις λειτουργικές ενημερώσεις κατά την εξαγωγή νέας κατάστασης από την παλιά, δομήστε τα εφέ γύρω από ζεύγη εγκατάστασης/καθαρισμού, να είστε ειλικρινείς και σαφείς με τους πίνακες εξαρτήσεων και να σέβεστε πάντα τους κανόνες των hooks, ώστε το React να μπορεί να παρακολουθεί αξιόπιστα τι ανήκει πού. Όταν ακολουθείτε αυτές τις αρχές, τα στοιχεία σας παραμένουν προβλέψιμα, οι παρενέργειές σας συμπεριφέρονται σωστά και η βάση κώδικα του React γίνεται πολύ πιο εύκολη στην εξέλιξη καθώς η εφαρμογή σας αναπτύσσεται.
