State and Lifecycle
These docs are old and won’t be updated. Go to react.dev for the new React docs.
These new documentation pages teach modern React and include live examples:
Bu səhifə React komponentin state və lifecycle anlayışlarını təqdim edir. Ətraflı komponent API kataloqu bu linkdə yerləşir.
Əvvəlki bölümlərin birindən işləyən saat nümunəsinə nəzər yetirək. Elementlərin render edilməsində biz UI dəyişməyin bir yolunu öyrəndik – root.render()
çağırmaqla:
const root = ReactDOM.createRoot(document.getElementById('root'));
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
root.render(element);}
setInterval(tick, 1000);
Bu bölümdə isə biz Clock
komponentini inkapsulyasiya və təkrar istifadə etməyi öyrənəcəyik. Bu komponent öz taymerini quraşdıracaq və saniyədə bir dəfə özünü yeniləyəcək.
Bunun üçün əvvəlcə Clock
komponentinə ayrılıqda nəzər yetirək:
const root = ReactDOM.createRoot(document.getElementById('root'));
function Clock(props) {
return (
<div> <h1>Hello, world!</h1> <h2>It is {props.date.toLocaleTimeString()}.</h2> </div> );
}
function tick() {
root.render(<Clock date={new Date()} />);}
setInterval(tick, 1000);
Bu komponentin önəmli çatışmazlığı var. Taymeri quraşdırma və özünü hər saniyə yeniləmə Clock
komponentinin daxilində olmalıdır.
Məqsədimiz bu komponenti elə reallaşdırmaqdır ki, komponent özü özünü yeniləməyi bilsin:
root.render(<Clock />);
Bunu yerinə yetirmək üçün Clock
komponentinə “state” əlavə etmək lazımdır.
State prop-a bənzəyir, lakin komponent tərəfindən tam idarə olunur və yalnız onun daxilində əlçatandır.
Funksiyanın sinifə çevrilməsi
Clock
kimi funksional komponenti sinif komponentinə 5 addımda çevirmək olar:
- İlkin komponentlə adı eyni olan,
React.Component
sinfini genişləndirən ES6 sinfi yaradaq. - Bu sinfə
render()
adlı boş metod əlavə edək. - Funksiyanın kodunu
render()
metoduna köçürək. render()
-in içindəprops
-uthis.props
ilə əvəzləyək.- Boş qalmış funksiyanı silək.
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
Öncəliklə funksiya kimi təyin edilən Clock
komponenti, indi sinif kimi təyin edilmişdir.
render
metodu hər dəfə yeniləmə baş tutduqda çağırılacaq. Lakin eyni DOM düyünü daxilində <Clock />
komponentini neçə dəfə istifadə etsək də, Clock
sinfinin yalnız bir nüsxəsi istifadə olunacaq. Bu hal bizə lokal state və lifecycle kimi əlavə xüsusiyyətləri istifadə etmə imkanı verir.
Sinfə lokal state əlavə edilməsi
date
prop-unu state-ə üç addımda çevirək:
render()
metodundathis.props.date
-ithis.state.date
ilə əvəz edək:
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div>
);
}
}
this.state
veriləninə ilkin dəyər təyin edən sinif konstruktoru əlavə edək:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()}; }
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
Diqqət yetirin ki, props
arqumenti baza konstruktora da ötürülür:
constructor(props) {
super(props); this.state = {date: new Date()};
}
Sinif komponentləri həmişə baza konstruktoru props
arqumentini ötürərək çağırmalıdırlar.
<Clock />
elementindəndate
prop-unu silək:
root.render(<Clock />);
Bir qədər sonra taymerin kodunu komponentə geri əlavə edəcəyik.
Yekun nəticə belədir:
class Clock extends React.Component {
constructor(props) { super(props); this.state = {date: new Date()}; }
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Clock />);
İndi isə Clock
komponentində taymer quraşdıraq və özünü hər saniyə yeniləməsini təmin edək.
Sinfə lifecycle metodlarının əlavə edilməsi
Tərkibində çox sayda komponent olan applikasiyalarda həmin komponentlər silinəndə, onların tutduğu resursların azad olunması olduqca önəmlidir.
Komponentin DOM-da ilk dəfə render olunmasına “mounting” deyilir. Bizim məqsədimiz hər dəfə “mounting” baş tutanda taymeri quraşdırmaqdır.
Komponentin DOM-dan silinməsi isə React-da “unmounting” adlanır. Bu proses zamanı taymeri yaddaşdan silmək gərəkdir.
Mounting və unmounting zamanı istədiyimiz kodu icra edən metodları təyin edək:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() { }
componentWillUnmount() { }
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
Bu metodlara “lifecycle metodları” deyilir.
componentDidMount()
metodu komponent DOM-da render olunduqdan dərhal sonra icra olunur. Taymeri quraşdırmaq üçün ən əlverişli yer buradır:
componentDidMount() {
this.timerID = setInterval( () => this.tick(), 1000 ); }
Diqqət yetirsək, taymerin ID-sini this
də saxladığımızı görərsiniz (this.timerID
).
this.props
React tərəfindən quraşdırılır, this.state
-in də xüsusi anlamı var. Bu ikisindən savayı sinfə hər hansı məlumat saxlamaq üçün məlumat axımında iştirak etməyən başqa verilənlər əlavə etmək olar (taymerin id-si kimi).
componentWillUnmount()
metodunda taymeri yaddaşdan siləcəyik:
componentWillUnmount() {
clearInterval(this.timerID); }
Sonunda tick()
metodunu yaradacağıq. Bu metodu Clock
komponenti saniyədə bir dəfə çağıracaq.
tick()
metodu this.setState()
çağırmaqla komponentin lokal state-ni yeniləyəcək.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() { this.setState({ date: new Date() }); }
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Clock />);
İndi Clock
hər saniyə dəyişir.
Gəlin bir daha hər şeyi təkrarlayaq və metodların çağırıldığı ardıcıllığa nəzər yetirək:
<Clock />
komponentiroot.render()
metoduna ötürüləndə ReactClock
sinfinin konstruktorunu çağırır. Bu komponent cari vaxtı göstərməlidir. Buna görə dəthis.state
-i cari vaxt obyekti ilə inisializasiya edir.- Daha sonra React
Clock
komponentininrender()
metodunu çağırır. Belə React ekranda nə göstərmək lazım olduğunu öyrənir. Bundan da sonra DOMClock
-un render nəticəsinə uyğun olaraq yenilənir. Clock
render olunub DOM-a əlavə olunandacomponentDidMount()
lifecycle metodu React tərəfindən çağırılır. Metodun içərisindəClock
komponenti brauzerə taymer quraşdırmağı əmr edir. Bu taymer saniyədə bir dəfətick()
metodunu çağıracaq.- Brauzer, gözləndiyi kimi,
tick()
metodunu hər saniyə çağırır. Bu metodun daxilindəClock
komponenti, cari vaxtı ötürməklə,setState()
metodunu çağırır.setState()
-in çağırılması React-ə state-in dəyişdiyini xəbər verir. React buna görə ekranda nə olmasını dəqiqləşdirmək üçün yenidənrender()
metodunu icra edir.render()
metodundathis.state.date
fərqli olduğundan, renderin nəticəsi fərqli vaxt göstərəcək. React DOM-u buna uyğun dəyişir. Clock
komponenti DOM-dan silinsəcomponentWillUnmount()
lifecycle metodu React tərəfindən çağırılacaq, taymer dayandırılacaq.
State-in düzgün istifadə edilməsi
setState()
haqqında bilməli olduğumuz üç şey var.
State-i birbaşa dəyişmək olmaz
Məsələn, bu kod komponenti yenidən render etməyəcək:
// Yanlış
this.state.comment = 'Hello';
Əvəzinə setState()
istifadə etmək lazımdır:
// Düzgün
this.setState({comment: 'Hello'});
this.state
-ə dəyər mənimsədilə biləcək yeganə yer konstruktordur.
State-in yenilənməsi asinxron ola bilər
React performansı təkmilləşdirmək üçün bir neçə setState()
çağırışını qruplaşdıra bilər.
this.props
və this.state
asinxron dəyişilə bildiyi üçün, onların sonrakı dəyərini hesablayanda indiki dəyərinə etibar etmək olmaz.
Məsələn, bu kod counter-i yeniləməkdə iflasa uğraya bilər.
// Yanlış
this.setState({
counter: this.state.counter + this.props.increment,
});
Bu problemi düzəltmək üçün, setState()
-in obyekt yerinə funksiya qəbul edən ikinci formasını istifadə etmək olar. Həmin funksiya birinci arqument kimi state-in əvvəlki dəyərini, ikinci arqument kimi isə propların yeniləmə zamanındakı dəyərini qəbul edir:
// Düzgün
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
Az öncəki misalda biz arrow funksiyasını istifadə etdik. Misal adi funksiyalar üçün də keçərlidir:
// Düzgün
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});
State yeniləmələri birləşdirilir
setState()
çağırılanda React ötürülən obyekti hazırki state-ə birləşdirir.
Misal üçün, state bir neçə sərbəst veriləndən ibarət ola bilər:
constructor(props) {
super(props);
this.state = {
posts: [], comments: [] };
}
Həmin verilənlər müstəqil olaraq setState()
vasitəsi ilə yenilənə bilər:
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts });
});
fetchComments().then(response => {
this.setState({
comments: response.comments });
});
}
Birləşdirmə dayazdır (shallow), yəni this.setState({comments})
çağırılanda this.state.posts
-u dəyişmir, amma this.state.comments
-i tamamilə əvəz edir.
Verilənlərin aşağı istiqamətdə axını
Nə valideyn, nə də uşaq komponenti digər komponentin state-inin olub olmadığını bilməyə məcbur deyil. Həmin komponentin funksiya və ya sinif kimi təyin olmağı da onlar üçün önəmli deyil.
Məhz buna görə state lokal və ya inkapsulyasiya olunmuş adlanır. Yalnız məxsus olduğu komponent daxilində əlçatandır, digər komponentlər onu görmür.
Komponent öz state-ini uşaq komponentlərinə (aşağı istiqamətdə) props kimi ötürə bilər:
<FormattedDate date={this.state.date} />
FormattedDate
komponenti date
-i props kimi qəbul edəcək. Lakin onun Clock
-un state-i, Clock
-un propları və ya manual olaraq daxil olduğundan xəbər tutmayacaq:
function FormattedDate(props) {
return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}
Buna “yuxarıdan-aşağı” (“top-down”) və ya “birtərəfli” (“unidirectional”) verilənlər axını deyilir. Hər bir state bir komponentə məxsusdur. Həmin state-in törəmələri yalnız komponentlər ağacında “aşağıda” olan komponentlərə təsir göstərə bilər.
Əgər komponent ağacını prop-ların şəlaləsi kimi təsəvvür etsək, hər bir komponentin state-i şəlaləyə qovuşan yeni su mənbəsidir. Hansıki təsadüfi bir yerdə şəlaləyə bitişir, amma yenə də aşağı axır.
Bütün komponentlərin izolyasiya olduğunu göstərmək üçün tərkibində üç <Clock>
olan App
komponenti yaradaq:
function App() {
return (
<div>
<Clock /> <Clock /> <Clock /> </div>
);
}
Hər bir Clock
öz taymerini quraşdırır və sərbəst yenilənir.
React applikasiyalarında komponentin state-nin olub olmaması gələcəkdə dəyişə bilən daxili detal sayılır. State-i olan komponentlər state-i olmayan komponentlərin içində istifadə oluna bilər. Əks bəyanətdə doğrudur.