Yüksək Dərəcəli Komponentlər
These docs are old and won’t be updated. Go to react.dev for the new React docs.
Higher-order components are not commonly used in modern React code.
Yüksək dərəcəli komponentlər (Higher-Order Component, HOC) React-də komponent məntiqini yenidən istifadə etmənin qabaqcıl texnikasıdır. HOC-lər özlüyündə React API-ın bir parçası deyil, React-in kompozisiyalı təbiətindən ortaya çıxan modeldir.
Qısacası, yüksək dərəcəli komponent bir komponenti parametr olaraq qəbul edib, yeni bir komponent qaytaran funksiyadır.
const EnhancedComponent = higherOrderComponent(WrappedComponent);Adi komponent propları UI-a çevirir, yüksək dərəcəli komponent isə komponenti başqa bir komponentə çevirir.
HOC-lər üçüncü tərəf React kitabxanalarında yayğındır, məsələn Redux-ın connect-i və ya Relay-in createFragmentContainer-i kimi.
Bu sənəddə yüksək dərəcəli komponentlərin niyə faydalı olduğunu və necə yazılacağını müzakirə edəcəyik.
HOC-lərin Cross-Cutting Concern-lər Üçün İstifadəsi
Qeyd
Əvvəllər cross-cutting concern-ləri ələ almaq üçün mixin-ləri təklif etdik. İndi isə, mixin-lərin xeyirindən daha çox ziyanı olduğunu anladıq. Mixin-ləri niyə ləğv etdiyimiz və mövcud komponentlərinizi necə dəyişə biləcəyiniz haqqında buradan oxuyun.
Komponentlər React-də kodu yenidən istifadə etmənin əsasıdır. Ancaq, bəzi problemlərin ənənəvi komponentlərlə həll oluna bilmədiyini görəcəyik.
Məsələn, gəlin xarici mənbədən aldığı yorumlar siyahısını render edən CommentList komponentinə baxaq:
class CommentList extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
// "DataSource" qlobal məlumatlar mənbəyidir
comments: DataSource.getComments()
};
}
componentDidMount() {
// Dəyişikliklərə abunə olma
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
// Dinləyicini təmizləmə
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
// Məlumat mənbəyi dəyişdikdə komponentin state-i yenilənir
this.setState({
comments: DataSource.getComments()
});
}
render() {
return (
<div>
{this.state.comments.map((comment) => (
<Comment comment={comment} key={comment.id} />
))}
</div>
);
}
}İndi isə, bənzər formada, tək bloq yazısına abunə olan yeni komponent yazaq:
class BlogPost extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
blogPost: DataSource.getBlogPost(props.id)
};
}
componentDidMount() {
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
blogPost: DataSource.getBlogPost(this.props.id)
});
}
render() {
return <TextBlock text={this.state.blogPost} />;
}
}CommentList və BlogPost eyni deyil — DataSource üzərində müxtəlif metodları çağırırlar və müxtəlif nəticələri render edirlər. Ancaq, əksər hissələri oxşardır:
- Mount zamanı dəyişiklik dinləyicisini
DataSource-a əlavə edir. - Məlumat qaynağı dəyişdikdə dinləyici içərisindən
setState-i çağırır. - Unmount zamanı dəyişiklik dinləyicisini silir.
Təsəvvür edin ki, böyük bir applikasiyada DataSource-a abunə olma və setState-i çağırma dəsti hər dəfə təkrarlanacaq. Bizə bu məntiqin bir yerdə müəyyən edərək, bir çox komponent arasında istifadəyə imkan verən abstraksiya lazımdır. Burada yüksək dərəcəli komponentlər üzə çıxır.
CommentList və BlogPost kimi komponentləri birbaşa yazmaq yerinə, bunları yaradan və DataSource-a abunə edən funksiya yaza bilərik. Bu funksiya abunə olduğu məlumatı prop kimi qəbul edən uşaq komponentini arqument kimi qəbul edəcək. Gəlin bu funksiyanı withSubscription adlandıraq:
const CommentListWithSubscription = withSubscription(
CommentList,
(DataSource) => DataSource.getComments()
);
const BlogPostWithSubscription = withSubscription(
BlogPost,
(DataSource, props) => DataSource.getBlogPost(props