Kontekst
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:
Kontekst məlumatları komponent ağacının hər səviyyəsində proplar göndərmədən məlumatları komponentlərə ötürməyə təmin edir.
Standart React applikasiyasında, məlumat yuxarıdan aşağı (valideyndən uşağa) proplar vasitəsi ilə göndərilir. Lakin bir çox komponentin istifadə etdiyi bəzi prop tiplərinin (məsələn dil seçimi, UI şablonun) göndərilməsi çox yorucu və çətin ola bilər. Kontekst ilə dəyərləri komponentlər arasında komponent ağacının hər səviyyəsində prop göndərmədən paylaşması mümkündür.
Nə Zaman Kontekst İşlətmək Lazımdır
Kontekst “qlobal” qəbul olunan məlumatları (məsələn avtorizasiya olunmuş istifadəçi, şablon, və ya seçilmiş dil) React komponentlər ağacında paylaşmaq üçün nəzərdə tutulmuşdur. Məsələn, aşağıdakı kodda biz Button komponentini dəyişmək üçün “theme” propunu bütün komponentlərdən bir-bir göndəririk:
class App extends React.Component {
render() {
return <Toolbar theme="dark" />;
}
}
function Toolbar(props) {
// Toolbar komponenti əlavə "theme" propu qəbul etməli və // bu propu ThemedButton komponentinə göndərməlidir. Applikasiyada hər bir // düymənin şablondan xəbəri olması üçün, "theme" propunu bütün // komponentlərdən keçmirmək çox yorucu ola bilər. return (
<div>
<ThemedButton theme={props.theme} /> </div>
);
}
class ThemedButton extends React.Component {
render() {
return <Button theme={this.props.theme} />;
}
}
Kontekst işlətdikdə isə, biz propları ara elementlərdən göndərməyə bilərik:
// Kontekst dəyərləri komponent ağacında hər komponentdən// keçmədən lazım olan komponentə ötürməyə icazə verir.// Cari şablon üçün yeni bir kontekst yaradın ("light" default dəyər kimi).const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// Provider-dən istifadə edərək cari şablon dəyərini aşağıdakı ağaca göndərin. // Dərinlikdən asılı olmayaraq, hər hansı bir komponent bu dəyəri oxuya bilər. // Bu misalda, biz "dark" yazısını cari dəyər kimi göndəririk. return (
<ThemeContext.Provider value="dark"> <Toolbar />
</ThemeContext.Provider>
);
}
}
// Ortadakı komponent artıq// şablon dəyərini açıq şəkildə göndərməməlidir.function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// Cari şablon dəyərini kontekstdən oxumaq üçün contextType təyin edin. // React ən yaxın olan Şablon Provider-ini tapıb kontekstin dəyərindən istifadə edəcək. // Bu misalda, cari şablonun dəyəri "dark"-dır. static contextType = ThemeContext;
render() {
return <Button theme={this.context} />; }
}
Kontekst İşlətməzdən Əvvəl
Kontekst əsasən məlumatın fərqli səviyyələrdə yerləşən bir neçə komponent tərəfindən işlənməsi üçündür. Bunu hər yerdə işlətməyin, çünki komponentin yenidən istifadəsini çətinləşdirir.
Əgər siz propları bir neçə səviyyədən göndərmək istəmirsinizsə, komponent kompozisiyası kontekstdən daha sadə həlldir.
Misal üçün, gəlin user
və avatarSize
proplarını mövcud olan Page
komponentindən bir neçə səviyyədə göndərək ki, dərində olan Link
və Avatar
komponentləri bu propları oxuya bilsinlər:
<Page user={user} avatarSize={avatarSize} />
// ... render edir ...
<PageLayout user={user} avatarSize={avatarSize} />
// ... render edir ...
<NavigationBar user={user} avatarSize={avatarSize} />
// ... render edir ...
<Link href={user.permalink}>
<Avatar user={user} size={avatarSize} />
</Link>
Əgər user
və avatarSize
propları yalnız Avatar
komponenti tərəfindən işlənəcəksə, bu propların bütün səviyyələrdə göndərilməsi lazımsızdır. Əgər Avatar
komponentinə yeni proplar lazım olsa, siz yenə lazım olan propları bütün ara komponentlərdən keçirməlisiniz.
Bu problemi kontekstsiz həll etməyin yolu Avatar
komponentinin özünü göndərməkdir. Bu zaman, ara komponentlərin user
və avatarSize
proplarını bilməsi lazım deyil:
function Page(props) {
const user = props.user;
const userLink = (
<Link href={user.permalink}>
<Avatar user={user} size={props.avatarSize} />
</Link>
);
return <PageLayout userLink={userLink} />;
}
// İndi bizdə aşağıdakı var
<Page user={user} avatarSize={avatarSize} />
// ... render edir ...
<PageLayout userLink={...} />
// ... render edir ...
<NavigationBar userLink={...} />
// ... render edir ...
{props.userLink}
Bu dəyişiklik ilə, yalnız ən yuxarıda olan Page komponenti, Link
və Avatar
komponentlərinin user
və avatarSize
proplarını işlətməyini bilir.
Bu kontrolun inversiyası applikasiyada göndərilən propların sayını azaldaraq və ana komponentlərə daha çox kontrol verərək bir neçə ssenaridə kodunuzu daha təmiz edir. Lakin, bu metod hər ssenari üçün düzgün seçim deyil: mürəkkəbiliyi komponent ağacında yüksək olan komponentlərə köçürdükdə, yuxarı səviyyəli komponentləri daha mürəkkəb edir və aşağı səviyyəli komponentlərin daha əyilgən olması lazım olur.
Siz komponentdə bir uşaq göstərməyə məhdud deyilsiniz. Siz bir neçə uşağı, hətta uşaqlar üçün bir neçə “yuva da” edə bilərsiniz (burada sənələşmişdir):
function Page(props) {
const user = props.user;
const content = <Feed user={user} />;
const topBar = (
<NavigationBar>
<Link href={user.permalink}>
<Avatar user={user} size={props.avatarSize} />
</Link>
</NavigationBar>
);
return (
<PageLayout
topBar={topBar}
content={content}
/>
);
}
Bu metod uşaqları yaxın valideyndən ayırmaq üçün kifayətdir. Əgər uşaq komponent, render etməzdən öncə valideyn ilə kommunikasiya qurmalıdırsa, siz render proplardan istifadə edə bilərsiniz.
Lakin, bəzən eyni məlumatlar komponent ağacında fərqli səviyyələrdə bir neçə komponent tərəfindən işlədilə bilməlidirlər. Kontekst belə məlumatları və bu məlumatlarda olan dəyişiklikləri, bütün aşağısında olan komponentlərə “yayımlaya” bilir. Bəzi nümunələrdə kontekst işlətmək alternativlərdən daha sadə ola bilər (dilin seçimi, şablon, məlumat keşi).
API
React.createContext
const MyContext = React.createContext(defaultValue);
Kontekst obyekti yaradır. React, Context obyektinə “abunə olan” komponentləri render edərkən, yuxarı səviyyədə ən yaxın olan Provider
-dən cari kontekst dəyərini oxuyacaq.
defaultValue
arqumenti yalnız komponentin yuxarı səviyyəsində Provider olmadığı zaman işlənir. Bu dəyər, komponentləri Provider ilə əhatə etmədən, ayrılıqda test etmək üçün faydalıdır. Qeyd: Provider dəyərinə undefined
göndərildikdə, qoşulan komponentlər defaultValue
-dan istifadə etmirlər.
Context.Provider
<MyContext.Provider value={/* bir dəyər */}>
Hər bir Context obyekti Provider adlı React komponenti ilə gəlir. Bu komponent kontekstdə olan dəyişikliklərə abunə olmaq istəyən komponentlərə imkan yaradır.
Provayder value
propu qəbul edir. Bu propun dəyəri abunə olan komponentlərə ötürülür. Bir Provider bir neçə Consumer komponentə goşula bilər. Ağacda dərində yerləşən provayderlər, yuxarıda olan provayderlərin dəyərlərini əvəz edir.
Provayderin aşağısında olan bütün istehlakçılar, Provayderin value
propu dəyişdikdə yenidən render edir. Provayderdən aşağıya məlumatların yayımlanması (.contextType
və useContext
daxil olmaqla) shouldComponentUpdate
funksiyasından asılı deyil. Bu deməkdir ki, yuxarı komponentdə heç bir komponent yenilənmədikdə belə Provider-ə abunə olan komponent yenilənəcək.
Dəyişikliklər yeni və köhnə dəyərlərin Object.is
alqoritminə bənzər bir alqoritm ilə müqayisəsi ilə təyin olunur.
Qeyd
Dəyişikliklər
value
-a obyekti göndərdikdə problem yarada bilərlər: Problemlər bölməsinə baxın.
Class.contextType
class MyClass extends React.Component {
componentDidMount() {
let value = this.context;
/* mount etdikdə MyContext-in dəyəri ilə kənar effekt edin */
}
componentDidUpdate() {
let value = this.context;
/* ... */
}
componentWillUnmount() {
let value = this.context;
/* ... */
}
render() {
let value = this.context;
/* MyContext-in dəyəri ilə render edin */
}
}
MyClass.contextType = MyContext;
contextType
sinif parametrinə React.createContext()
ilə yaranmış Context obyekti təyin edilə bilər. Bu sizə ən yaxında olan kontekstin dəyərini this.context
-dən oxumağa icazə verir. Siz bu dəyişəndə olan dəyəri render funksiyası daxil olmaqla bütün lifecycle funksiyalarından istifadə edə bilərsiniz.
Qeyd:
Siz bu API ilə yalnız bir kontekstə abunə ola bilərsiniz. Əgər sizə birdən çox kontekst lazımdırsa Bir Neçə Kontekstin İstehlakı bölməsindən oxuya bilərsiniz.
Əgər siz eksperimental olan public sinif sahəsi sintaksisindən istifadə edirsinizsə, siz static sinif sahəsindən istifadə edib
contextType
-ı inisializasiya edə bilərsiniz.
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context;
/* dəyər əsasında render et */
}
}
Context.Consumer
<MyContext.Consumer>
{value => /* kontekst dəyəri əsasında render et */}
</MyContext.Consumer>
Kontekst dəyişikliklərinə abunə olan React komponenti. Bu komponent ilə funksiya komponentinin kontekstə abunə olması mümkündür.
Funksiyanın uşaq kimi olmasını tələb edir. Bu funksiya, kontekstin cari dəyərini qəbul edir və React nodu qaytarır. Funksiyaya göndərilən value
arqumenti, komponent ağacında bu komponentə ən yaxın olan Provider-in value
propu ilə eynidir. Əgər provayder yoxdursa, value
arqumenti createContext()
-ə keçirilən defaultValue
propuna bərabər olacaq.
Qeyd
‘funksiyanın uşaq kimi olması’ patterni haqqında daha ətraflı məlumat üçün, render propları sənədinə baxın.
Context.displayName
Kontekst obyekti displayName
mətn parametri qəbul edir. React DevTools bu parametrdən istifadə edərək kontekti hansı adla göstərəcəyini müəyyənləşdirir.
Məsələn, aşağıdakı komponent DevTools-da “MyDisplayName” kimi göstəriləcək:
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
<MyContext.Provider> // DevTools-da "MyDisplayName.Provider" göstəriləcək
<MyContext.Consumer> // DevTools-da "MyDisplayName.Consumer" göstəriləcək
Misallar
Dinamik Kontekst
Şablon üçün dinamik dəyərlər işlədən daha kompleks misal:
theme-context.js
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext( themes.dark // default dəyər);
themed-button.js
import {ThemeContext} from './theme-context';
class ThemedButton extends React.Component {
render() {
let props = this.props;
let theme = this.context; return (
<button
{...props}
style={{backgroundColor: theme.background}}
/>
);
}
}
ThemedButton.contextType = ThemeContext;
export default ThemedButton;
app.js
import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';
// ThemedButton-dan istifadə edən ara komponent
function Toolbar(props) {
return (
<ThemedButton onClick={props.changeTheme}>
Change Theme
</ThemedButton>
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
};
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
}
render() {
// ThemeProvider-də olan ThemedButton düyməsi // state-də olan şablondan istifadə edərkən, xaricindəki komponent // default olan dark şablondan istifadə edir return (
<Page>
<ThemeContext.Provider value={this.state.theme}> <Toolbar changeTheme={this.toggleTheme} /> </ThemeContext.Provider> <Section>
<ThemedButton /> </Section>
</Page>
);
}
}
const root = ReactDOM.createRoot(
document.getElementById('root')
);
root.render(<App />);
Konteksti Bir-Birindən Keçən Komponentdən Yeniləmək
Çox vaxt konteksti komponent ağacının dərinliklərində olan bir komponentdən yeniləmək lazım olur. Bu halda, siz kontekstdən dəyərləri Consumer-lərin yeniləməsi üçün funksiya göndərə bilərsiniz:
theme-context.js
// createContext-də işlənən default dəyərin forması
// Consumer-lərin gözlədiyi dəyərdir!
export const ThemeContext = React.createContext({
theme: themes.dark, toggleTheme: () => {},});
theme-toggler-button.js
import {ThemeContext} from './theme-context';
function ThemeTogglerButton() {
// Theme Toggler Button theme-dən əlavə // toggleTheme funksiyasını da kontekstdən qəbul edir return (
<ThemeContext.Consumer>
{({theme, toggleTheme}) => ( <button
onClick={toggleTheme}
style={{backgroundColor: theme.background}}>
Toggle Theme
</button>
)}
</ThemeContext.Consumer>
);
}
export default ThemeTogglerButton;
app.js
import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';
class App extends React.Component {
constructor(props) {
super(props);
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
// Dəyəri yeniləyən funksiyanında state-də olduğundan, // bu funksiya da kontekst provayderindən göndəriləcək this.state = {
theme: themes.light,
toggleTheme: this.toggleTheme, };
}
render() {
// Bütün state provayderdən göndəriləcək return (
<ThemeContext.Provider value={this.state}> <Content />
</ThemeContext.Provider>
);
}
}
function Content() {
return (
<div>
<ThemeTogglerButton />
</div>
);
}
const root = ReactDOM.createRoot(
document.getElementById('root')
);
root.render(<App />);
Bir Neçə Kontekstin İstehlakı
Kontekstin yenidən render edilməsinin tez olması üçün React hər kontekst consumer-i üçün komponent ağacında yeni nod yaratmalıdır.
// Şablon konteksti, default dəyəri "light"-dır
const ThemeContext = React.createContext('light');
// Login etmiş istifadəçi konteksti
const UserContext = React.createContext({
name: 'Guest',
});
class App extends React.Component {
render() {
const {signedInUser, theme} = this.props;
// App komponenti ilkin kontekst dəyərləri təmin edir
return (
<ThemeContext.Provider value={theme}> <UserContext.Provider value={signedInUser}> <Layout />
</UserContext.Provider> </ThemeContext.Provider> );
}
}
function Layout() {
return (
<div>
<Sidebar />
<Content />
</div>
);
}
// Komponent bir neçə kontekstə abunə ola bilər
function Content() {
return (
<ThemeContext.Consumer> {theme => ( <UserContext.Consumer> {user => ( <ProfilePage user={user} theme={theme} /> )} </UserContext.Consumer> )} </ThemeContext.Consumer> );
}
Əgər 2 və ya daha çox kontekst dəyəri tez-tez birlikdə işlədilirsə, siz bu kontekstlərin dəyərlərini birlikdə təmin edən xüsusi bir render prop komponenti düzəldə bilərsiniz.
Problemlər
Konteskt yenidən render etmə zamanını, dəyərin referensi əsasında müəyyənləşdirir. Bu səbəbdən, provider yenidən render etdikdə, consumer-lərdə istənilməyən renderlər ola bilər. Məsələn, aşağıdakı kodda value
üçün hər zaman yeni obyekt yarandığından, bütün consumer-lər yenidən render edirlər:
class App extends React.Component {
render() {
return (
<MyContext.Provider value={{something: 'something'}}> <Toolbar />
</MyContext.Provider>
);
}
}
Bu problemi həll etmək üçün, dəyəri valideynin state-inə qaldırın:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'}, };
}
render() {
return (
<MyContext.Provider value={this.state.value}> <Toolbar />
</MyContext.Provider>
);
}
}
Köhnə API
Qeyd
Əvvəl React eksperimental kontekst API-ı ilə gəlirdi. Bu köhnə API, React-in bütün 16.x buraxılışlarında dəstəklənəcək. Lakin applikasiyaların yeni API-a miqrasiya edilməyi tövsiyə edilir. Köhnə API, React-in gələcək buraxılışlarında silinəcək. Köhnə kontekst haqqında buradan oxuya bilərsiniz.