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.Componentsinfini 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.propsilə ə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.dateilə ə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.stateverilə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əndateprop-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ə ReactClocksinfinin 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
Clockkomponentininrender()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. Clockrender olunub DOM-a əlavə olunandacomponentDidMount()lifecycle metodu React tərəfindən çağırılır. Metodun içərisindəClockkomponenti 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əClockkomponenti, 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.datefərqli olduğundan, renderin nəticəsi fərqli vaxt göstərəcək. React DOM-u buna uyğun dəyişir. Clockkomponenti 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.