diff --git a/src/content/learn/passing-data-deeply-with-context.md b/src/content/learn/passing-data-deeply-with-context.md index e81678c8e..1340c49de 100644 --- a/src/content/learn/passing-data-deeply-with-context.md +++ b/src/content/learn/passing-data-deeply-with-context.md @@ -1,48 +1,48 @@ --- -title: Passing Data Deeply with Context +title: تمرير البيانات بعمق باستخدام السياق (Context) --- -Usually, you will pass information from a parent component to a child component via props. But passing props can become verbose and inconvenient if you have to pass them through many components in the middle, or if many components in your app need the same information. *Context* lets the parent component make some information available to any component in the tree below it—no matter how deep—without passing it explicitly through props. +عادةً، ستقوم بتمرير المعلومات من المُكوّن الأب (parent component) إلى المُكوّن الابن (child component) عبر الخصائص (props). ولكن، قد يُصبح تمرير الخصائص مُطوّلاً ومُرهقاً إذا اضطررت لتمريرها عبر العديد من المُكوّنات الوسيطة، أو إذا كانت العديد من المُكوّنات في تطبيقك تحتاج إلى نفس المعلومات. يتيح السياق (Context) للمُكوّن الأب جعل بعض المعلومات مُتاحة لأي مُكوّن يقع تحته في شجرة المُكوّنات —بغض النظر عن مدى عُمقه— دون الحاجة لتمريرها صراحةً عبر الخصائص. -- What "prop drilling" is -- How to replace repetitive prop passing with context -- Common use cases for context -- Common alternatives to context +- ما هو "تمرير الخصائص المتكرر" (prop drilling)؟ +- كيف تستبدل تمرير الخصائص المتكرر باستخدام السياق (Context)؟ +- حالات الاستخدام الشائعة للسياق (Context) +- البدائل الشائعة للسياق (Context) -## The problem with passing props {/*the-problem-with-passing-props*/} +## مشكلة تمرير الخصائص {/*the-problem-with-passing-props*/} -[Passing props](/learn/passing-props-to-a-component) is a great way to explicitly pipe data through your UI tree to the components that use it. +يُعد [تمرير الخصائص](/learn/passing-props-to-a-component) طريقة رائعة لتوجيه البيانات صراحةً عبر شجرة واجهة المستخدم (UI tree) إلى المُكوّنات التي تستخدمها. -But passing props can become verbose and inconvenient when you need to pass some prop deeply through the tree, or if many components need the same prop. The nearest common ancestor could be far removed from the components that need data, and [lifting state up](/learn/sharing-state-between-components) that high can lead to a situation called "prop drilling". +ولكن، قد يُصبح تمرير الخصائص (props) مُطوّلاً ومُرهقاً عندما تحتاج إلى تمرير خاصية ما بعمق عبر الشجرة، أو إذا كانت العديد من المُكوّنات (Components) تحتاج إلى الخاصية ذاتها. قد يكون السلف المشترك الأقرب (nearest common ancestor) بعيداً جداً عن المُكوّنات التي تحتاج إلى البيانات، ورفع الحالة (state) إلى هذا المستوى العالي قد يؤدي إلى حالة تُعرف باسم "التمرير العميق للخصائص" (prop drilling). - + -Lifting state up +رفع الحالة (Lifting state up) - + -Prop drilling +التمرير العميق للخصائص (Prop drilling) -Wouldn't it be great if there were a way to "teleport" data to the components in the tree that need it without passing props? With React's context feature, there is! +ألن يكون رائعاً لو كانت هناك طريقة لـ "نقل" (teleport) البيانات إلى المُكوّنات التي تحتاجها في الشجرة دون تمرير الخصائص (props)؟ مع ميزة السياق (Context) في React، هذا ممكن! -## Context: an alternative to passing props {/*context-an-alternative-to-passing-props*/} +## السياق: بديل لتمرير الخصائص {/*context-an-alternative-to-passing-props*/} -Context lets a parent component provide data to the entire tree below it. There are many uses for context. Here is one example. Consider this `Heading` component that accepts a `level` for its size: +يُتيح السياق (Context) للمُكوّن الأب توفير البيانات للشجرة بأكملها التي تقع أسفل منه. هناك العديد من الاستخدامات للسياق (Context). إليك أحد الأمثلة. تأمل مُكوّن الترويسة (Heading) هذا، والذي يقبل خاصية المستوى `level` لتحديد حجمه: @@ -53,15 +53,16 @@ import Section from './Section.js'; export default function Page() { return (
- Title - Heading - Sub-heading - Sub-sub-heading - Sub-sub-sub-heading - Sub-sub-sub-sub-heading + العنوان الرئيسي + الترويسة + ترويسة فرعية + ترويسة فرعية ثانية + ترويسة فرعية ثالثة + ترويسة فرعية رابعة
); } + ``` ```js src/Section.js @@ -72,6 +73,7 @@ export default function Section({ children }) { ); } + ``` ```js src/Heading.js @@ -90,9 +92,10 @@ export default function Heading({ level, children }) { case 6: return
{children}
; default: - throw Error('Unknown level: ' + level); + throw Error('مستوى غير معروف: ' + level); } } + ``` ```css @@ -102,11 +105,12 @@ export default function Heading({ level, children }) { border-radius: 5px; border: 1px solid #aaa; } + ```
-Let's say you want multiple headings within the same `Section` to always have the same size: +لنفترض أن لديك عدة ترويسات داخل القسم `Section` نفسه، وتريد أن تكون جميعها بنفس الحجم دائماً: @@ -117,25 +121,26 @@ import Section from './Section.js'; export default function Page() { return (
- Title + العنوان الرئيسي
- Heading - Heading - Heading + الترويسة + الترويسة + الترويسة
- Sub-heading - Sub-heading - Sub-heading + ترويسة فرعية + ترويسة فرعية + ترويسة فرعية
- Sub-sub-heading - Sub-sub-heading - Sub-sub-heading + ترويسة فرعية ثانية + ترويسة فرعية ثانية + ترويسة فرعية ثانية
); } + ``` ```js src/Section.js @@ -146,6 +151,7 @@ export default function Section({ children }) { ); } + ``` ```js src/Heading.js @@ -164,9 +170,10 @@ export default function Heading({ level, children }) { case 6: return
{children}
; default: - throw Error('Unknown level: ' + level); + throw Error('مستوى غير معروف: ' + level); } } + ``` ```css @@ -176,59 +183,62 @@ export default function Heading({ level, children }) { border-radius: 5px; border: 1px solid #aaa; } + ```
-Currently, you pass the `level` prop to each `` separately: +حالياً، تقوم بتمرير الخاصية `level` إلى كل `` على حدة: ```js
- About - Photos - Videos + حول + الصور + الفيديوهات
+ ``` -It would be nice if you could pass the `level` prop to the `
` component instead and remove it from the ``. This way you could enforce that all headings in the same section have the same size: +سيكون من الرائع لو كان بإمكانك تمرير الخاصية `level` إلى المُكوّن `
` بدلاً من ذلك وإزالتها من ``. بهذه الطريقة، يمكنك ضمان أن جميع الترويسات في القسم نفسه لها الحجم ذاته: ```js
- About - Photos - Videos + حول + الصور + الفيديوهات
+ ``` -But how can the `` component know the level of its closest `
`? **That would require some way for a child to "ask" for data from somewhere above in the tree.** +ولكن كيف يمكن للمُكوّن `` معرفة المستوى الخاص بأقرب `
` إليه؟ **سيتطلب ذلك وجود طريقة ما للمُكوّن الابن لـ "طلب" البيانات من مكان أعلى منه في الشجرة.** -You can't do it with props alone. This is where context comes into play. You will do it in three steps: +لا يمكنك القيام بذلك باستخدام الخصائص (props) وحدها. هنا يأتي دور السياق (Context). ستقوم بذلك في ثلاث خطوات: -1. **Create** a context. (You can call it `LevelContext`, since it's for the heading level.) -2. **Use** that context from the component that needs the data. (`Heading` will use `LevelContext`.) -3. **Provide** that context from the component that specifies the data. (`Section` will provide `LevelContext`.) +1. **إنشاء** سياق (Context). (يمكنك تسميته `LevelContext`، بما أنه خاص بمستوى الترويسة.) +2. **استخدام** ذلك السياق (Context) من المُكوّن الذي يحتاج إلى البيانات. (سيستخدم `Heading` السياق `LevelContext`.) +3. **توفير** ذلك السياق (Context) من المُكوّن الذي يحدد البيانات. (سيوفر `Section` السياق `LevelContext`.) -Context lets a parent--even a distant one!--provide some data to the entire tree inside of it. +يُتيح السياق (Context) للمُكوّن الأب (Parent component) —حتى وإن كان بعيداً!— توفير بعض البيانات للشجرة بأكملها الموجودة بداخله. - + -Using context in close children +استخدام السياق (Context) مع المُكوّنات الأبناء القريبة - + -Using context in distant children +استخدام السياق (Context) مع المُكوّنات الأبناء البعيدة -### Step 1: Create the context {/*step-1-create-the-context*/} +### الخطوة 1: إنشاء السياق {/*step-1-create-the-context*/} -First, you need to create the context. You'll need to **export it from a file** so that your components can use it: +أولاً، تحتاج إلى إنشاء السياق (Context). ستحتاج إلى **تصديره من ملف** (export it from a file) حتى تتمكن مُكوّناتك (Components) من استخدامه: @@ -239,25 +249,26 @@ import Section from './Section.js'; export default function Page() { return (
- Title + العنوان الرئيسي
- Heading - Heading - Heading + الترويسة + الترويسة + الترويسة
- Sub-heading - Sub-heading - Sub-heading + ترويسة فرعية + ترويسة فرعية + ترويسة فرعية
- Sub-sub-heading - Sub-sub-heading - Sub-sub-heading + ترويسة فرعية ثانية + ترويسة فرعية ثانية + ترويسة فرعية ثانية
); } + ``` ```js src/Section.js @@ -268,6 +279,7 @@ export default function Section({ children }) {
); } + ``` ```js src/Heading.js @@ -286,15 +298,17 @@ export default function Heading({ level, children }) { case 6: return
{children}
; default: - throw Error('Unknown level: ' + level); + throw Error('مستوى غير معروف: ' + level); } } + ``` ```js src/LevelContext.js active import { createContext } from 'react'; export const LevelContext = createContext(1); + ``` ```css @@ -304,61 +318,67 @@ export const LevelContext = createContext(1); border-radius: 5px; border: 1px solid #aaa; } + ``` -The only argument to `createContext` is the _default_ value. Here, `1` refers to the biggest heading level, but you could pass any kind of value (even an object). You will see the significance of the default value in the next step. +الوسيط الوحيد لدالة `createContext` هو القيمة *الافتراضية* (default value). هنا، يشير `1` إلى مستوى الترويسة الأكبر، ولكن يمكنك تمرير أي نوع من القيم (حتى كائن (object)). سترى أهمية القيمة الافتراضية في الخطوة التالية. -### Step 2: Use the context {/*step-2-use-the-context*/} +### الخطوة 2: استخدام السياق {/*step-2-use-the-context*/} -Import the `useContext` Hook from React and your context: +استورد الخطاف (Hook) `useContext` من React والسياق (Context) الخاص بك: ```js import { useContext } from 'react'; import { LevelContext } from './LevelContext.js'; + ``` -Currently, the `Heading` component reads `level` from props: +حالياً، يقرأ المُكوّن (Component) `Heading` الخاصية `level` من الخصائص (props): ```js export default function Heading({ level, children }) { // ... } + ``` -Instead, remove the `level` prop and read the value from the context you just imported, `LevelContext`: +بدلاً من ذلك، قم بإزالة الخاصية (prop) `level` واقرأ القيمة من السياق (Context) الذي استوردته للتو، `LevelContext`: ```js {2} export default function Heading({ children }) { const level = useContext(LevelContext); // ... } + ``` -`useContext` is a Hook. Just like `useState` and `useReducer`, you can only call a Hook immediately inside a React component (not inside loops or conditions). **`useContext` tells React that the `Heading` component wants to read the `LevelContext`.** +`useContext` هو خطاف (Hook). تماماً مثل `useState` و `useReducer`، لا يمكنك استدعاء خطاف (Hook) إلا بشكل مباشر داخل مُكوّن (Component) React (وليس داخل الحلقات التكرارية أو الشروط). **يُخبر `useContext` React أن المُكوّن `Heading` يريد قراءة `LevelContext`.** -Now that the `Heading` component doesn't have a `level` prop, you don't need to pass the level prop to `Heading` in your JSX like this anymore: +الآن وبما أن المُكوّن (Component) `Heading` لا يملك الخاصية `level`، فلن تحتاج إلى تمريرها إلى `Heading` داخل JSX الخاص بك بهذا الشكل بعد الآن: ```js
- Sub-sub-heading - Sub-sub-heading - Sub-sub-heading + ترويسة فرعية ثانية + ترويسة فرعية ثانية + ترويسة فرعية ثانية
+ ``` -Update the JSX so that it's the `Section` that receives it instead: +قم بتحديث الـ JSX بحيث يكون المُكوّن (Component) `Section` هو من يتلقاها بدلاً من ذلك: ```jsx
- Sub-sub-heading - Sub-sub-heading - Sub-sub-heading + ترويسة فرعية ثانية + ترويسة فرعية ثانية + ترويسة فرعية ثانية
+ ``` -As a reminder, this is the markup that you were trying to get working: +للتذكير، هذا هو الهيكل الذي كنت تحاول جعله يعمل: @@ -369,25 +389,26 @@ import Section from './Section.js'; export default function Page() { return (
- Title + العنوان الرئيسي
- Heading - Heading - Heading + الترويسة + الترويسة + الترويسة
- Sub-heading - Sub-heading - Sub-heading + ترويسة فرعية + ترويسة فرعية + ترويسة فرعية
- Sub-sub-heading - Sub-sub-heading - Sub-sub-heading + ترويسة فرعية ثانية + ترويسة فرعية ثانية + ترويسة فرعية ثانية
); } + ``` ```js src/Section.js @@ -398,6 +419,7 @@ export default function Section({ children }) {
); } + ``` ```js src/Heading.js @@ -420,15 +442,17 @@ export default function Heading({ children }) { case 6: return
{children}
; default: - throw Error('Unknown level: ' + level); + throw Error('مستوى غير معروف: ' + level); } } + ``` ```js src/LevelContext.js import { createContext } from 'react'; export const LevelContext = createContext(1); + ``` ```css @@ -438,17 +462,18 @@ export const LevelContext = createContext(1); border-radius: 5px; border: 1px solid #aaa; } + ``` -Notice this example doesn't quite work, yet! All the headings have the same size because **even though you're *using* the context, you have not *provided* it yet.** React doesn't know where to get it! +لاحظ أن هذا المثال لا يعمل تماماً حتى الآن! كل الترويسات لها نفس الحجم لأنك **على الرغم من أنك *تستخدم* السياق (Context)، إلا أنك لم تقم بـ *توفيره* بعد.** لا تعرف React من أين يمكنها الحصول عليه! -If you don't provide the context, React will use the default value you've specified in the previous step. In this example, you specified `1` as the argument to `createContext`, so `useContext(LevelContext)` returns `1`, setting all those headings to `

`. Let's fix this problem by having each `Section` provide its own context. +إذا لم تقم بتوفير السياق (Context)، ستستخدم React القيمة الافتراضية التي حددتها في الخطوة السابقة. في هذا المثال، قمت بتحديد `1` كوسيط لـ `createContext`، لذا فإن `useContext(LevelContext)` تُرجع `1`، وتجعل جميع الترويسات تبدو كـ `

`. دعنا نصلح هذه المشكلة بجعل كل `Section` توفر سياقها (Context) الخاص بها. -### Step 3: Provide the context {/*step-3-provide-the-context*/} +### الخطوة 3: توفير السياق {/*step-3-provide-the-context*/} -The `Section` component currently renders its children: +يقوم المُكوّن (Component) `Section` حالياً بعرض أبنائه: ```js export default function Section({ children }) { @@ -458,9 +483,10 @@ export default function Section({ children }) {

); } + ``` -**Wrap them with a context provider** to provide the `LevelContext` to them: +**قم بتغليفهم بمُوفّر سياق** (context provider) لتوفير `LevelContext` لهم: ```js {1,6,8} import { LevelContext } from './LevelContext.js'; @@ -474,9 +500,10 @@ export default function Section({ level, children }) {
); } + ``` -This tells React: "if any component inside this `
` asks for `LevelContext`, give them this `level`." The component will use the value of the nearest `` in the UI tree above it. +هذا يخبر React: "إذا طلب أي مُكوّن (Component) داخل هذا الـ `
` السياق `LevelContext`، أعطه هذه الخاصية `level`". سيستخدم المُكوّن قيمة أقرب `` في شجرة واجهة المستخدم (UI tree) الموجودة أعلاه. @@ -487,25 +514,26 @@ import Section from './Section.js'; export default function Page() { return (
- Title + العنوان الرئيسي
- Heading - Heading - Heading + الترويسة + الترويسة + الترويسة
- Sub-heading - Sub-heading - Sub-heading + ترويسة فرعية + ترويسة فرعية + ترويسة فرعية
- Sub-sub-heading - Sub-sub-heading - Sub-sub-heading + ترويسة فرعية ثانية + ترويسة فرعية ثانية + ترويسة فرعية ثانية
); } + ``` ```js src/Section.js @@ -520,6 +548,7 @@ export default function Section({ level, children }) {
); } + ``` ```js src/Heading.js @@ -542,15 +571,17 @@ export default function Heading({ children }) { case 6: return
{children}
; default: - throw Error('Unknown level: ' + level); + throw Error('مستوى غير معروف: ' + level); } } + ``` ```js src/LevelContext.js import { createContext } from 'react'; export const LevelContext = createContext(1); + ``` ```css @@ -560,19 +591,20 @@ export const LevelContext = createContext(1); border-radius: 5px; border: 1px solid #aaa; } + ``` -It's the same result as the original code, but you did not need to pass the `level` prop to each `Heading` component! Instead, it "figures out" its heading level by asking the closest `Section` above: +هذه هي النتيجة نفسها كالكود الأصلي، لكنك لم تحتج إلى تمرير الخاصية (prop) `level` إلى كل مُكوّن (Component) `Heading`! بدلاً من ذلك، فإنه "يكتشف" مستوى الترويسة الخاص به عن طريق سؤال أقرب `Section` يقع فوقه: -1. You pass a `level` prop to the `
`. -2. `Section` wraps its children into ``. -3. `Heading` asks the closest value of `LevelContext` above with `useContext(LevelContext)`. +1. تمرر الخاصية (prop) `level` إلى الـ `
`. +2. يُغلّف `Section` أبناءه (children) داخل ``. +3. يطلب المُكوّن `Heading` أقرب قيمة لـ `LevelContext` أعلاه باستخدام `useContext(LevelContext)`. -## Using and providing context from the same component {/*using-and-providing-context-from-the-same-component*/} +## استخدام وتوفير السياق من المُكوّن نفسه {/*using-and-providing-context-from-the-same-component*/} -Currently, you still have to specify each section's `level` manually: +حالياً، لا يزال يتعين عليك تحديد الخاصية `level` لكل قسم يدوياً: ```js export default function Page() { @@ -583,9 +615,10 @@ export default function Page() { ...
... + ``` -Since context lets you read information from a component above, each `Section` could read the `level` from the `Section` above, and pass `level + 1` down automatically. Here is how you could do it: +بما أن السياق (Context) يتيح لك قراءة المعلومات من مُكوّن (Component) أعلاه، يمكن لكل `Section` قراءة الخاصية `level` من الـ `Section` الذي يعلوه، وتمرير `level + 1` إلى الأسفل تلقائياً. إليك كيف يمكنك القيام بذلك: ```js src/Section.js {5,8} import { useContext } from 'react'; @@ -601,9 +634,10 @@ export default function Section({ children }) {
); } + ``` -With this change, you don't need to pass the `level` prop *either* to the `
` or to the ``: +مع هذا التغيير، أنت لا تحتاج إلى تمرير الخاصية (prop) `level` *لا* إلى الـ `
` *ولا* إلى ``: @@ -614,25 +648,26 @@ import Section from './Section.js'; export default function Page() { return (
- Title + العنوان الرئيسي
- Heading - Heading - Heading + الترويسة + الترويسة + الترويسة
- Sub-heading - Sub-heading - Sub-heading + ترويسة فرعية + ترويسة فرعية + ترويسة فرعية
- Sub-sub-heading - Sub-sub-heading - Sub-sub-heading + ترويسة فرعية ثانية + ترويسة فرعية ثانية + ترويسة فرعية ثانية
); } + ``` ```js src/Section.js @@ -649,6 +684,7 @@ export default function Section({ children }) {
); } + ``` ```js src/Heading.js @@ -659,7 +695,7 @@ export default function Heading({ children }) { const level = useContext(LevelContext); switch (level) { case 0: - throw Error('Heading must be inside a Section!'); + throw Error('يجب أن تكون الترويسة داخل قسم (Section)!'); case 1: return

{children}

; case 2: @@ -673,15 +709,17 @@ export default function Heading({ children }) { case 6: return
{children}
; default: - throw Error('Unknown level: ' + level); + throw Error('مستوى غير معروف: ' + level); } } + ``` ```js src/LevelContext.js import { createContext } from 'react'; export const LevelContext = createContext(0); + ``` ```css @@ -691,23 +729,24 @@ export const LevelContext = createContext(0); border-radius: 5px; border: 1px solid #aaa; } + ``` -Now both `Heading` and `Section` read the `LevelContext` to figure out how "deep" they are. And the `Section` wraps its children into the `LevelContext` to specify that anything inside of it is at a "deeper" level. +الآن يقرأ كل من `Heading` و `Section` السياق `LevelContext` لمعرفة مدى "عمقهم". ويقوم `Section` بتغليف أبنائه في `LevelContext` لتحديد أن أي شيء بداخله يقع في مستوى "أعمق". -This example uses heading levels because they show visually how nested components can override context. But context is useful for many other use cases too. You can pass down any information needed by the entire subtree: the current color theme, the currently logged in user, and so on. +يستخدم هذا المثال مستويات الترويسات (headings) لأنها تُظهر بشكل مرئي كيف يمكن للمُكوّنات (Components) المتداخلة تجاوز (override) السياق (Context). لكن السياق (Context) مفيد في العديد من حالات الاستخدام الأخرى أيضاً. يمكنك تمرير أي معلومات تحتاجها الشجرة الفرعية (subtree) بأكملها للأسفل: سمة الألوان الحالية (color theme)، المستخدم المسجل دخوله حالياً، وما إلى ذلك. -## Context passes through intermediate components {/*context-passes-through-intermediate-components*/} +## يمر السياق عبر المُكوّنات الوسيطة {/*context-passes-through-intermediate-components*/} -You can insert as many components as you like between the component that provides context and the one that uses it. This includes both built-in components like `
` and components you might build yourself. +يمكنك إدراج أي عدد تريده من المُكوّنات (Components) بين المُكوّن الذي يوفر السياق (Context) والمُكوّن الذي يستخدمه. يشمل هذا كلاً من المُكوّنات (Components) المدمجة مثل `
` والمُكوّنات التي قد تبنيها بنفسك. -In this example, the same `Post` component (with a dashed border) is rendered at two different nesting levels. Notice that the `` inside of it gets its level automatically from the closest `
`: +في هذا المثال، يتم تصيير المُكوّن (Component) نفسه `Post` (والذي يمتلك حدوداً متقطعة) في مستويين متداخلين مختلفين. لاحظ أن الـ `` بداخله يحصل على مستواه تلقائياً من أقرب `
`: @@ -718,10 +757,10 @@ import Section from './Section.js'; export default function ProfilePage() { return (
- My Profile + ملفي الشخصي
@@ -731,7 +770,7 @@ export default function ProfilePage() { function AllPosts() { return (
- Posts + المنشورات
); @@ -740,14 +779,14 @@ function AllPosts() { function RecentPosts() { return (
- Recent Posts + أحدث المنشورات
); @@ -763,6 +802,7 @@ function Post({ title, body }) {
); } + ``` ```js src/Section.js @@ -782,6 +822,7 @@ export default function Section({ children, isFancy }) {
); } + ``` ```js src/Heading.js @@ -792,7 +833,7 @@ export default function Heading({ children }) { const level = useContext(LevelContext); switch (level) { case 0: - throw Error('Heading must be inside a Section!'); + throw Error('يجب أن تكون الترويسة داخل قسم (Section)!'); case 1: return

{children}

; case 2: @@ -806,15 +847,17 @@ export default function Heading({ children }) { case 6: return
{children}
; default: - throw Error('Unknown level: ' + level); + throw Error('مستوى غير معروف: ' + level); } } + ``` ```js src/LevelContext.js import { createContext } from 'react'; export const LevelContext = createContext(0); + ``` ```css @@ -828,62 +871,65 @@ export const LevelContext = createContext(0); .fancy { border: 4px dashed pink; } + ``` -You didn't do anything special for this to work. A `Section` specifies the context for the tree inside it, so you can insert a `` anywhere, and it will have the correct size. Try it in the sandbox above! +لم تقم بفعل أي شيء خاص لكي يعمل هذا. يُحدد الـ `Section` السياق (Context) للشجرة التي بداخله، لذا يمكنك إدراج `` في أي مكان، وسيكون له الحجم الصحيح. جربه في بيئة الاختبار (sandbox) أعلاه! + +**يتيح لك السياق (Context) كتابة مُكوّنات (Components) "تتكيف مع محيطها" وتعرض نفسها بشكل مختلف بناءً على *المكان* (أو بعبارة أخرى، *في أي سياق (Context)*) الذي يتم تصييرها فيه.** -**Context lets you write components that "adapt to their surroundings" and display themselves differently depending on _where_ (or, in other words, _in which context_) they are being rendered.** +قد يُذكرك عمل السياق (Context) بـ [وراثة خصائص CSS (CSS property inheritance).](https://developer.mozilla.org/en-US/docs/Web/CSS/inheritance) في CSS، يمكنك تحديد `color: blue` لـ `
`، وأي عقدة DOM بداخله، بغض النظر عن مدى عمقها، سترث هذا اللون ما لم تتجاوزه عقدة DOM أخرى في المنتصف عبر تحديد `color: green`. وبالمثل، في React، الطريقة الوحيدة لتجاوز سياق (Context) قادم من الأعلى هي تغليف الأبناء (children) في مُوفّر سياق (Context provider) بقيمة مختلفة. -How context works might remind you of [CSS property inheritance.](https://developer.mozilla.org/en-US/docs/Web/CSS/inheritance) In CSS, you can specify `color: blue` for a `
`, and any DOM node inside of it, no matter how deep, will inherit that color unless some other DOM node in the middle overrides it with `color: green`. Similarly, in React, the only way to override some context coming from above is to wrap children into a context provider with a different value. +في CSS، الخصائص المختلفة مثل `color` و `background-color` لا تتجاوز بعضها البعض. يمكنك تعيين الخاصية `color` لجميع عناصر `
` إلى اللون الأحمر دون التأثير على الخاصية `background-color`. وبالمثل، **لا تتجاوز سياقات React (React contexts) المختلفة بعضها البعض.** كل سياق (Context) تقوم بإنشائه باستخدام `createContext()` يكون منفصلاً تماماً عن السياقات الأخرى، ويربط معاً المُكوّنات (Components) التي تستخدم وتوفر *ذلك السياق بالذات*. يمكن لمُكوّن (Component) واحد أن يستخدم أو يوفر العديد من السياقات المختلفة دون أي مشكلة. -In CSS, different properties like `color` and `background-color` don't override each other. You can set all `
`'s `color` to red without impacting `background-color`. Similarly, **different React contexts don't override each other.** Each context that you make with `createContext()` is completely separate from other ones, and ties together components using and providing *that particular* context. One component may use or provide many different contexts without a problem. +## قبل أن تستخدم السياق {/*before-you-use-context*/} -## Before you use context {/*before-you-use-context*/} +استخدام السياق (Context) أمر مغرٍ جداً! ومع ذلك، هذا يعني أيضاً أنه من السهل جداً الإفراط في استخدامه. **مجرد أنك تحتاج إلى تمرير بعض الخصائص (props) لعدة مستويات عميقة لا يعني أنه يجب عليك وضع تلك المعلومات في السياق (Context).** -Context is very tempting to use! However, this also means it's too easy to overuse it. **Just because you need to pass some props several levels deep doesn't mean you should put that information into context.** +إليك بعض البدائل التي يجب عليك أخذها في الاعتبار قبل استخدام السياق (Context): -Here's a few alternatives you should consider before using context: +1. **ابدأ بـ [تمرير الخصائص (props).**](https://www.google.com/search?q=/learn/passing-props-to-a-component) إذا كانت مُكوّناتك (Components) ليست بسيطة، فليس من غير المألوف تمرير عشرات الخصائص (props) للأسفل عبر عشرات المُكوّنات. قد يبدو الأمر شاقاً، ولكنه يجعل من الواضح جداً أي المُكوّنات تستخدم أي بيانات! سيكون الشخص الذي يصون كودك ممتناً لأنك جعلت تدفق البيانات صريحاً باستخدام الخصائص (props). +2. **استخرج المُكوّنات و[مرر JSX كـ `children](https://www.google.com/search?q=/learn/passing-props-to-a-component%23passing-jsx-as-children)` إليها.** إذا كنت تمرر بعض البيانات عبر العديد من طبقات المُكوّنات (Components) الوسيطة التي لا تستخدم تلك البيانات (وتكتفي بتمريرها للأسفل)، فهذا يعني غالباً أنك نسيت استخراج بعض المُكوّنات على طول الطريق. على سبيل المثال، ربما تمرر خصائص (props) بيانات مثل `posts` إلى مُكوّنات مرئية لا تستخدمها مباشرة، مثل ``. بدلاً من ذلك، اجعل `Layout` يقبل `children` كخاصية (prop)، وقم بتصيير ``. هذا يقلل من عدد الطبقات بين المُكوّن الذي يحدد البيانات والمُكوّن الذي يحتاجها. -1. **Start by [passing props.](/learn/passing-props-to-a-component)** If your components are not trivial, it's not unusual to pass a dozen props down through a dozen components. It may feel like a slog, but it makes it very clear which components use which data! The person maintaining your code will be glad you've made the data flow explicit with props. -2. **Extract components and [pass JSX as `children`](/learn/passing-props-to-a-component#passing-jsx-as-children) to them.** If you pass some data through many layers of intermediate components that don't use that data (and only pass it further down), this often means that you forgot to extract some components along the way. For example, maybe you pass data props like `posts` to visual components that don't use them directly, like ``. Instead, make `Layout` take `children` as a prop, and render ``. This reduces the number of layers between the component specifying the data and the one that needs it. +إذا لم تعمل أي من هذه المقاربات بشكل جيد معك، فكر حينها في استخدام السياق (Context). -If neither of these approaches works well for you, consider context. +## حالات استخدام السياق {/*use-cases-for-context*/} -## Use cases for context {/*use-cases-for-context*/} +* **السمات (Theming):** إذا كان تطبيقك يتيح للمستخدم تغيير مظهره (مثل الوضع الليلي)، يمكنك وضع مُوفّر سياق (Context provider) في أعلى تطبيقك، واستخدام ذلك السياق (Context) في المُكوّنات (Components) التي تحتاج إلى تعديل مظهرها المرئي. +* **الحساب الحالي (Current account):** قد تحتاج العديد من المُكوّنات (Components) إلى معرفة المستخدم المسجل دخوله حالياً. وضعه في سياق (Context) يجعله مريحاً للقراءة في أي مكان في الشجرة. تتيح لك بعض التطبيقات أيضاً تشغيل حسابات متعددة في نفس الوقت (مثل ترك تعليق كمستخدم مختلف). في تلك الحالات، قد يكون من المريح تغليف جزء من واجهة المستخدم (UI) بمُوفّر سياق (provider) متداخل يحمل قيمة حساب حالي مختلفة. +* **التوجيه (Routing):** تستخدم معظم حلول التوجيه السياق (Context) داخلياً للاحتفاظ بالمسار الحالي (route). هكذا "يعرف" كل رابط ما إذا كان نشطاً أم لا. إذا قمت ببناء الموجّه (router) الخاص بك، فربما ترغب في فعل ذلك أيضاً. +* **إدارة الحالة (Managing state):** مع نمو تطبيقك، قد ينتهي بك الأمر بوجود الكثير من الحالات (state) بالقرب من أعلى تطبيقك. قد ترغب العديد من المُكوّنات (Components) البعيدة بالأسفل في تغييرها. من الشائع [استخدام مُقلّل (reducer) مع سياق (Context)](https://www.google.com/search?q=/learn/scaling-up-with-reducer-and-context) لإدارة الحالات المعقدة وتمريرها للأسفل إلى المُكوّنات البعيدة دون الكثير من العناء. -* **Theming:** If your app lets the user change its appearance (e.g. dark mode), you can put a context provider at the top of your app, and use that context in components that need to adjust their visual look. -* **Current account:** Many components might need to know the currently logged in user. Putting it in context makes it convenient to read it anywhere in the tree. Some apps also let you operate multiple accounts at the same time (e.g. to leave a comment as a different user). In those cases, it can be convenient to wrap a part of the UI into a nested provider with a different current account value. -* **Routing:** Most routing solutions use context internally to hold the current route. This is how every link "knows" whether it's active or not. If you build your own router, you might want to do it too. -* **Managing state:** As your app grows, you might end up with a lot of state closer to the top of your app. Many distant components below may want to change it. It is common to [use a reducer together with context](/learn/scaling-up-with-reducer-and-context) to manage complex state and pass it down to distant components without too much hassle. - -Context is not limited to static values. If you pass a different value on the next render, React will update all the components reading it below! This is why context is often used in combination with state. +لا يقتصر السياق (Context) على القيم الثابتة. إذا مررت قيمة مختلفة في التصيير (render) التالي، ستقوم React بتحديث جميع المُكوّنات (Components) التي تقرأه بالأسفل! هذا هو السبب في أن السياق يُستخدم غالباً بالاشتراك مع الحالة (state). -In general, if some information is needed by distant components in different parts of the tree, it's a good indication that context will help you. +بشكل عام، إذا كانت بعض المعلومات مطلوبة من قبل مُكوّنات (Components) بعيدة في أجزاء مختلفة من الشجرة، فهذا مؤشر جيد على أن السياق (Context) سيساعدك. -* Context lets a component provide some information to the entire tree below it. -* To pass context: - 1. Create and export it with `export const MyContext = createContext(defaultValue)`. - 2. Pass it to the `useContext(MyContext)` Hook to read it in any child component, no matter how deep. - 3. Wrap children into `` to provide it from a parent. -* Context passes through any components in the middle. -* Context lets you write components that "adapt to their surroundings". -* Before you use context, try passing props or passing JSX as `children`. +* يتيح السياق (Context) لمُكوّن (Component) توفير بعض المعلومات للشجرة بأكملها التي تقع أسفله. +* لتمرير السياق (Context): +1. قم بإنشائه وتصديره باستخدام `export const MyContext = createContext(defaultValue)`. +2. مرره إلى الخطاف (Hook) عبر `useContext(MyContext)` لقراءته في أي مُكوّن (Component) ابن، بغض النظر عن مدى عمقه. +3. غلف الأبناء (children) داخل `` لتوفيره من مُكوّن أب (parent component). + + +* يمر السياق (Context) عبر أي مُكوّنات (Components) وسيطة في المنتصف. +* يتيح لك السياق (Context) كتابة مُكوّنات (Components) "تتكيف مع محيطها". +* قبل استخدام السياق (Context)، جرب تمرير الخصائص (props) أو تمرير JSX كـ `children`. -#### Replace prop drilling with context {/*replace-prop-drilling-with-context*/} +#### استبدال التمرير العميق للخصائص باستخدام السياق {/*replace-prop-drilling-with-context*/} -In this example, toggling the checkbox changes the `imageSize` prop passed to each ``. The checkbox state is held in the top-level `App` component, but each `` needs to be aware of it. +في هذا المثال، يؤدي تبديل مربع الاختيار (checkbox) إلى تغيير الخاصية (prop) المسماة `imageSize` والممررة إلى كل مُكوّن ``. يتم الاحتفاظ بحالة (state) مربع الاختيار في المُكوّن ذي المستوى الأعلى `App`، ولكن كل `` بحاجة إلى أن يكون على دراية بها. -Currently, `App` passes `imageSize` to `List`, which passes it to each `Place`, which passes it to the `PlaceImage`. Remove the `imageSize` prop, and instead pass it from the `App` component directly to `PlaceImage`. +حالياً، يمرر الـ `App` الخاصية `imageSize` إلى `List`، والذي يمررها إلى كل `Place`، والذي بدوره يمررها إلى `PlaceImage`. قم بإزالة الخاصية (prop) `imageSize`، وبدلاً من ذلك مررها من المُكوّن (Component) `App` مباشرة إلى `PlaceImage`. -You can declare context in `Context.js`. +يمكنك التصريح عن السياق (Context) في الملف `Context.js`. @@ -905,7 +951,7 @@ export default function App() { setIsLarge(e.target.checked); }} /> - Use large images + استخدام صور كبيرة
@@ -950,59 +996,63 @@ function PlaceImage({ place, imageSize }) { /> ); } + ``` ```js src/Context.js + ``` ```js src/data.js export const places = [{ id: 0, - name: 'Bo-Kaap in Cape Town, South Africa', - description: 'The tradition of choosing bright colors for houses began in the late 20th century.', - imageId: 'K9HVAGH' + name: 'مدينة صنعاء القديمة، اليمن', + description: 'تتميز بطراز معماري فريد ومبانٍ مزينة بـ "القمرية".', + imageId: 'K9HVAGH' }, { id: 1, - name: 'Rainbow Village in Taichung, Taiwan', - description: 'To save the houses from demolition, Huang Yung-Fu, a local resident, painted all 1,200 of them in 1924.', + name: 'البتراء (المدينة الوردية)، الأردن', + description: 'مدينة تاريخية منحوتة في الصخر، وتُعد واحدة من عجائب الدنيا السبع الجديدة.', imageId: '9EAYZrt' }, { id: 2, - name: 'Macromural de Pachuca, Mexico', - description: 'One of the largest murals in the world covering homes in a hillside neighborhood.', + name: 'أهرامات الجيزة، مصر', + description: 'من أقدم المعالم التاريخية في العالم، وتُعد شاهداً على عظمة الحضارة الفرعونية.', imageId: 'DgXHVwu' }, { id: 3, - name: 'Selarón Staircase in Rio de Janeiro, Brazil', - description: 'This landmark was created by Jorge Selarón, a Chilean-born artist, as a "tribute to the Brazilian people."', + name: 'العُلا (مدائن صالح)، السعودية', + description: 'موقع أثري مذهل يتميز بالواجهات الصخرية المنحوتة بدقة وسط الطبيعة الصحراوية.', imageId: 'aeO3rpI' }, { id: 4, - name: 'Burano, Italy', - description: 'The houses are painted following a specific color system dating back to 16th century.', + name: 'شفشاون (المدينة الزرقاء)، المغرب', + description: 'مدينة جبلية ساحرة تتميز بمبانيها وشوارعها المطلية بتدرجات اللون الأزرق.', imageId: 'kxsph5C' }, { id: 5, - name: 'Chefchaouen, Marocco', - description: 'There are a few theories on why the houses are painted blue, including that the color repels mosquitos or that it symbolizes sky and heaven.', + name: 'برج خليفة في دبي، الإمارات', + description: 'أطول مبنى في العالم، ويُعد تحفة معمارية وهندسية حديثة.', imageId: 'rTqKo46' }, { id: 6, - name: 'Gamcheon Culture Village in Busan, South Korea', - description: 'In 2009, the village was converted into a cultural hub by painting the houses and featuring exhibitions and art installations.', + name: 'قلعة بعلبك، لبنان', + description: 'تضم واحدة من أضخم وأفضل الهياكل الرومانية المحفوظة في العالم.', imageId: 'ZfQOOzf' }]; + ``` ```js src/utils.js export function getImageUrl(place) { return ( - 'https://i.imgur.com/' + + '[https://i.imgur.com/](https://i.imgur.com/)' + place.imageId + 'l.jpg' ); } + ``` ```css @@ -1014,15 +1064,16 @@ li { gap: 20px; align-items: center; } + ```
-Remove `imageSize` prop from all the components. +قم بإزالة الخاصية (prop) `imageSize` من جميع المُكوّنات (Components). -Create and export `ImageSizeContext` from `Context.js`. Then wrap the List into `` to pass the value down, and `useContext(ImageSizeContext)` to read it in the `PlaceImage`: +قم بإنشاء وتصدير `ImageSizeContext` من `Context.js`. ثم قم بتغليف المُكوّن `List` داخل `` لتمرير القيمة للأسفل، واستخدم `useContext(ImageSizeContext)` لقراءتها داخل `PlaceImage`: @@ -1047,7 +1098,7 @@ export default function App() { setIsLarge(e.target.checked); }} /> - Use large images + استخدام صور كبيرة
@@ -1087,61 +1138,65 @@ function PlaceImage({ place }) { /> ); } + ``` ```js src/Context.js import { createContext } from 'react'; export const ImageSizeContext = createContext(500); + ``` ```js src/data.js export const places = [{ id: 0, - name: 'Bo-Kaap in Cape Town, South Africa', - description: 'The tradition of choosing bright colors for houses began in the late 20th century.', - imageId: 'K9HVAGH' + name: 'مدينة صنعاء القديمة، اليمن', + description: 'تتميز بطراز معماري فريد ومبانٍ مزينة بـ "القمرية".', + imageId: 'K9HVAGH' }, { id: 1, - name: 'Rainbow Village in Taichung, Taiwan', - description: 'To save the houses from demolition, Huang Yung-Fu, a local resident, painted all 1,200 of them in 1924.', + name: 'البتراء (المدينة الوردية)، الأردن', + description: 'مدينة تاريخية منحوتة في الصخر، وتُعد واحدة من عجائب الدنيا السبع الجديدة.', imageId: '9EAYZrt' }, { id: 2, - name: 'Macromural de Pachuca, Mexico', - description: 'One of the largest murals in the world covering homes in a hillside neighborhood.', + name: 'أهرامات الجيزة، مصر', + description: 'من أقدم المعالم التاريخية في العالم، وتُعد شاهداً على عظمة الحضارة الفرعونية.', imageId: 'DgXHVwu' }, { id: 3, - name: 'Selarón Staircase in Rio de Janeiro, Brazil', - description: 'This landmark was created by Jorge Selarón, a Chilean-born artist, as a "tribute to the Brazilian people".', + name: 'العُلا (مدائن صالح)، السعودية', + description: 'موقع أثري مذهل يتميز بالواجهات الصخرية المنحوتة بدقة وسط الطبيعة الصحراوية.', imageId: 'aeO3rpI' }, { id: 4, - name: 'Burano, Italy', - description: 'The houses are painted following a specific color system dating back to 16th century.', + name: 'شفشاون (المدينة الزرقاء)، المغرب', + description: 'مدينة جبلية ساحرة تتميز بمبانيها وشوارعها المطلية بتدرجات اللون الأزرق.', imageId: 'kxsph5C' }, { id: 5, - name: 'Chefchaouen, Marocco', - description: 'There are a few theories on why the houses are painted blue, including that the color repels mosquitos or that it symbolizes sky and heaven.', + name: 'برج خليفة في دبي، الإمارات', + description: 'أطول مبنى في العالم، ويُعد تحفة معمارية وهندسية حديثة.', imageId: 'rTqKo46' }, { id: 6, - name: 'Gamcheon Culture Village in Busan, South Korea', - description: 'In 2009, the village was converted into a cultural hub by painting the houses and featuring exhibitions and art installations.', + name: 'قلعة بعلبك، لبنان', + description: 'تضم واحدة من أضخم وأفضل الهياكل الرومانية المحفوظة في العالم.', imageId: 'ZfQOOzf' }]; + ``` ```js src/utils.js export function getImageUrl(place) { return ( - 'https://i.imgur.com/' + + '[https://i.imgur.com/](https://i.imgur.com/)' + place.imageId + 'l.jpg' ); } + ``` ```css @@ -1153,11 +1208,12 @@ li { gap: 20px; align-items: center; } + ```
-Note how components in the middle don't need to pass `imageSize` anymore. +لاحظ كيف أن المُكوّنات (Components) في المنتصف لم تعد بحاجة إلى تمرير `imageSize` بعد الآن.
diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index 1ff5be72e..189722405 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -187,7 +187,7 @@ "path": "/learn/extracting-state-logic-into-a-reducer" }, { - "title": "Passing Data Deeply with Context", + "title": "تمرير البيانات بعمق باستخدام السياق (Context)", "path": "/learn/passing-data-deeply-with-context" }, {