مفهوم کانتکست(context) در react
فهرست مطالب
Toggleمفهوم کانتکست(context) در react
با سلام خدمت همه عزیزان. در این مقاله با من همراه باشید تا مفهوم context در ریکت با هم برررسی کنیم.
خب بریم سراغ ادامه مقاله…
لازم به ذکر است که این مقاله از سایت اصلی خود ریکت گردآوری شده است
“Context” یک روش فراهم میکند تا بتوانید دادهها را از طریق درخت مولفهها منتقل کنید بدون اینکه به صورت دستی در هر سطح آنها را منتقل کنید.
در یک برنامه React معمولی، دادهها به صورت بالا به پایین (از والد به فرزند) از طریق props منتقل میشوند، اما استفاده از این روش برای برخی از انواع props (مانند ترجیحات محلی، تم رابط کاربری) که توسط بسیاری از مولفهها در یک برنامه نیاز است، ممکن است سنگین باشد. “Context” یک روش فراهم میکند تا بتوانید مقادیری مانند اینها را بین مولفهها به اشتراک بگذارید بدون اینکه لازم باشد یک prop به صورت صریح از طریق هر سطح از درخت منتقل شود.
حالا چه زمانی از کانتکست ها استفاده میکنیم؟زمان استفاده از Context: “Context” برای به اشتراک گذاری دادههایی که میتوانند به عنوان “گلوبال” برای یک درخت از مولفههای React در نظر گرفته شوند، مانند کاربر فعلی احراز هویت شده، تم یا زبان ترجیحی. به عنوان مثال، در کد زیر، ما به صورت دستی یک prop به نام “theme” را از طریق مولفه دکمه منتقل میکنیم تا بتوانیم آن را برای استایل دهی به مولفه دکمه استفاده کنیم:
class App extends React.Component {
render() {
return ;
}
}
function Toolbar(props) {
// The Toolbar component must take an extra "theme" prop
// and pass it to the ThemedButton. This can become painful
// if every single button in the app needs to know the theme
// because it would have to be passed through all components.
return (
);
}
class ThemedButton extends React.Component {
render() {
return ;
}
}
با استفاده از “Context”، میتوانیم از انتقال props از طریق عناصر واسطهای خودداری کنیم:
// Context lets us pass a value deep into the component tree
// without explicitly threading it through every component.
// Create a context for the current theme (with "light" as the default).
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// Use a Provider to pass the current theme to the tree below.
// Any component can read it, no matter how deep it is.
// In this example, we're passing "dark" as the current value.
return (
);
}
}
// A component in the middle doesn't have to
// pass the theme down explicitly anymore.
function Toolbar() {
return (
);
}
class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use its value.
// In this example, the current theme is "dark".
static contextType = ThemeContext;
render() {
return ;
}
}
قبل از استفاده از Context: “Context” اصولا زمانی استفاده میشود که بخواهیم به دادهای توسط بسیاری از مولفهها در سطوح مختلف دسترسی داشته باشیم. از آن به صورت محتاطانه استفاده کنید زیرا باعث سختتر شدن استفاده مجدد از مولفهها میشود.
اگر فقط میخواهید از انتقال برخی از props از طریق سطوح مختلف خودداری کنید، ترکیب مولفهها اغلب راه حلی سادهتر از Context است.
به عنوان مثال، فرض کنید یک مولفه صفحه (Page) وجود دارد که یک prop به نام “user” و “avatarSize” را چندین سطح پایینتر منتقل میکند تا مولفههای ژرفا نهفته شده مانند Link و Avatar بتوانند آن را خوانده و استفاده کنند:
// ... which renders ...
// ... which renders ...
// ... which renders ...
ممکن است احساس کنید انتقال props کاربر و avatarSize از طریق چندین سطح اضافی است اگر در نهایت فقط مولفه Avatar به واقعیت نیاز دارد. همچنین اذیتکننده است که هر زمان که مولفه Avatar نیاز به props بیشتری از بالا دارد، شما باید آنها را به تمامی سطوح واسطی نیز اضافه کنید.
یک راه برای حل این مسئله بدون استفاده از Context این است که خود مولفه Avatar را انتقال دهید تا مولفههای واسطی نیازی به اطلاعات props کاربر یا avatarSize نداشته باشند:
function Page(props) {
const user = props.user;
const userLink = (
);
return ;
}
// Now, we have:
// ... which renders ...
// ... which renders ...
// ... which renders ...
{props.userLink}
با این تغییر، تنها مولفه بالاترین Page نیاز به اطلاعات استفاده از کاربر و avatarSize در مولفههای Link و Avatar دارد.
این معکوس کردن کنترل میتواند در بسیاری از موارد کد شما را تمیزتر کند با کاهش تعداد propsی که باید از طریق برنامهی شما منتقل شود و دادن بیشتری کنترل به مولفههای ریشه. این معکوس کردن، با این حال، در همه موارد بهترین انتخاب نیست؛ انتقال پیچیدگی بیشتر به سطح بالاتر در درخت، موجب میشود که مولفههای سطح بالاتر پیچیدهتر شوند و مجبور به انعطاف بیشتری باشند تا آنچه شما میخواهید.
شما محدود به یک فرزند برای یک مولفه نیستید. شما میتوانید چندین فرزند را منتقل کنید، یا حتی چندین “اسلات” جداگانه برای فرزندان داشته باشید، همانطور که در اینجا توضیح داده شده است:
function Page(props) {
const user = props.user;
const content = ;
const topBar = (
);
return (
);
}
این الگو برای بسیاری از موارد کافی است زمانی که نیاز به جداسازی یک فرزند از والدین فوری آن است. شما میتوانید با استفاده از render props این الگو را به مراتب گسترش دهید اگر فرزند قبل از رندر شدن نیاز به ارتباط با والد دارد.
با این حال، گاهی اوقات نیاز است که همان داده توسط بسیاری از مولفهها در درخت قابل دسترسی باشد، و در سطوح تو درو. Context به شما اجازه میدهد تا چنین دادهها و تغییراتی که در آنها اتفاق میافتد، را به تمامی مولفههای زیرانتقال دهید. مثالهای معمولی که استفاده از Context ممکن است سادهتر از جایگزینها باشد شامل مدیریت محل فعلی، تم یا حافظه نهان داده است.
خب حالا بریم سراغ استفاده از create context
const MyContext = React.createContext(defaultValue);
React.createContext ساخت یک شیء Context را فراهم میکند. زمانی که React یک مولفه را رندر میکند که به این شیء Context مشترک میشود، ارزش فعلی Context را از نزدیکترین Provider مطابق بالای آن در درخت میخواند.
پارامتر defaultValue تنها زمانی استفاده میشود که یک مولفه مطابق Provider مطابق بالای خود در درخت نداشته باشد. ارزش پیشفرض میتواند برای تست کردن مولفهها به صورت جداگانه بدون بستهبندی آنها مفید باشد. توجه: ارسال undefined به عنوان مقدار Provider منجر به استفاده از defaultValue توسط مولفههای مصرفکننده نمیشود.
استفاده از provider
هر شیء Context با یک مولفه Provider React همراه است که به مولفههای مصرفکننده اجازه میدهد تا به تغییرات Context مشترک مشترک شوند.
مولفه Provider یک prop به نام value را برای ارسال به مولفههای مصرفکننده که فرزندان این Provider هستند، میپذیرد. یک Provider میتواند به چندین مصرفکننده متصل شود. Providers میتوانند به صورت تو در تو باشند تا مقادیر را در عمقترین نقاط درخت بازنویسی کنند.
همه مصرفکنندگانی که فرزندان یک Provider هستند، هر زمان که prop مقدار Provider تغییر کند، مجدداً رندر خواهند شد. انتشار از Provider به مصرفکنندگان فرزند خود (شامل .contextType و useContext) نیازی به روش shouldComponentUpdate ندارد، بنابراین مصرفکننده بروزرسانی میشود حتی زمانی که یک مولفه پدر یک بروزرسانی را از دست میدهد.
تغییرات توسط مقایسه مقادیر جدید و قدیمی با استفاده از الگوریتم مشابه Object.is تعیین میشون
استفاده از contextType
class MyClass extends React.Component {
componentDidMount() {
let value = this.context;
/* perform a side-effect at mount using the value of MyContext */
}
componentDidUpdate() {
let value = this.context;
/* ... */
}
componentWillUnmount() {
let value = this.context;
/* ... */
}
render() {
let value = this.context;
/* render something based on the value of MyContext */
}
}
MyClass.contextType = MyContext;
ویژگی contextType روی یک کلاس میتواند یک شیء Context که توسط React.createContext() ایجاد شده است، اختصاص داده شود. استفاده از این ویژگی به شما امکان میدهد که مقدار فعلی نزدیکترین از نوع Context را با استفاده از this.context مصرف کنید. شما میتوانید این را در هر یک از متدهای چرخه عمر از جمله تابع render مرجعی قرار دهید.
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context;
/* render something based on the value */
}
}
استفاده از Consumer
{value => /* render something based on the context value */}
یک مولفه React که به تغییرات Context مشترک مشترک میشود. استفاده از این مولفه به شما امکان میدهد تا به یک Context در یک مولفه تابع مشترک شوید.
نیازمند یک تابع به عنوان فرزند است. این تابع مقدار فعلی Context را دریافت میکند و یک گره React را برمیگرداند. آرگومان مقداری که به تابع منتقل میشود برابر با prop مقدار نزدیکترین Provider برای این Context در بالای درخت است. اگر هیچ Provider برای این Context در بالا وجود نداشته باشد، آرگومان مقدار برابر با defaultValue که به createContext() منتقل شده بود، خواهد بود.
استفاده از displayName
شیء Context یک خصوصیت رشتهای displayName را پذیرفته است. React DevTools از این رشته برای تعیین نمایش در مورد Context استفاده میکند.
به عنوان مثال، مولفه زیر به عنوان MyDisplayName در DevTools ظاهر میشود:
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
// "MyDisplayName.Provider" in DevTools
// "MyDisplayName.Consumer" in DevTools
یک مثال پیچیدهتر با مقادیر پویا برای تم:
theme-context.js
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext(
themes.dark // default value
);
themed-button.js
import {ThemeContext} from './theme-context';
class ThemedButton extends React.Component {
render() {
let props = this.props;
let theme = this.context;
return (
);
}
}
ThemedButton.contextType = ThemeContext;
export default ThemedButton;
app.js
import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';
// An intermediate component that uses the ThemedButton
function Toolbar(props) {
return (
Change Theme
);
}
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() {
// The ThemedButton button inside the ThemeProvider
// uses the theme from state while the one outside uses
// the default dark theme
return (
);
}
}
const root = ReactDOM.createRoot(
document.getElementById('root')
);
root.render( );
Updating Context from a Nested Component اکثراً نیاز است که از یک مولفه که در یک نقطه عمیقاً در درخت مولفهها قرار دارد، Context را بهروز کنیم. در این صورت میتوانید یک تابع را از طریق Context به پایین منتقل کنید تا به مصرفکنندگان این امکان داده شود تا Context را بهروز کنند:
theme-context.js
// Make sure the shape of the default value passed to
// createContext matches the shape that the consumers expect!
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
});
theme-toggler-button.js
import {ThemeContext} from './theme-context';
function ThemeTogglerButton() {
// The Theme Toggler Button receives not only the theme
// but also a toggleTheme function from the context
return (
{({theme, toggleTheme}) => (
)}
);
}
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,
}));
};
// State also contains the updater function so it will
// be passed down into the context provider
this.state = {
theme: themes.light,
toggleTheme: this.toggleTheme,
};
}
render() {
// The entire state is passed to the provider
return (
);
}
}
function Content() {
return (
);
}
const root = ReactDOM.createRoot(
document.getElementById('root')
);
root.render( );
Consuming Multiple Contexts برای حفظ سریع بودن بازنویسی Context، React نیاز دارد که هر مصرفکننده Context را به عنوان یک گره جداگانه در درخت قرار دهد.
// Theme context, default to light theme
const ThemeContext = React.createContext('light');
// Signed-in user context
const UserContext = React.createContext({
name: 'Guest',
});
class App extends React.Component {
render() {
const {signedInUser, theme} = this.props;
// App component that provides initial context values
return (
);
}
}
function Layout() {
return (
);
}
// A component may consume multiple contexts
function Content() {
return (
{theme => (
{user => (
)}
)}
);
}
اگر دو یا بیشتر مقدار Context اغلب بههم استفاده میشوند، ممکن است بخواهید یک مولفه render prop اختصاصی ایجاد کنید که هر دو را فراهم کند.
نکات مهم زیرا Context از هویت مرجع برای تعیین زمان بازنویسی استفاده میکند، برخی مسائلی وجود دارد که ممکن است باعث بازنویسیهای ناخواسته در مصرفکنندگان شود زمانی که والدین یک ارائهدهنده مجدداً بازنویسی میشوند. به عنوان مثال، کد زیر همه مصرفکنندگان را هر بار که ارائهدهنده دوباره بازنویسی میشود، بازنویسی میکند زیرا همیشه یک شیء جدید برای مقدار ایجاد میشود:
class App extends React.Component {
render() {
return (
);
}
}
برای دور زدن این موضوع، مقدار را به حالت والد ببرید:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}
render() {
return (
);
}
}
خب دوستان رسیدیم به پایان این مقاله. این مقاله از سایت اصلی ریکت برای شما عزیزان گردآوری شده است
منبع : https://legacy.reactjs.org