نعم ، تتولى React تطوير الواجهة الأمامية. السؤال هو لماذا.

تحديث: هذه المقالة هي الآن جزء من كتابي "React.js Beyond The Basics" . اقرأ النسخة المحدثة من هذا المحتوى والمزيد حول React على jscomplete.com/react-beyond-basics .

فيما يلي بعض الأسباب التي جعلت React أصبحت شائعة جدًا بهذه السرعة:

  • العمل مع DOM API صعب. يمنح React المطورين بشكل أساسي القدرة على العمل باستخدام متصفح افتراضي يكون أكثر سهولة من المتصفح الحقيقي. يعمل متصفح React الافتراضي بمثابة وكيل بين المطور والمتصفح الحقيقي.
  • تمكن React المطورين من وصف واجهات المستخدم الخاصة بهم بشكل إعلاني ونمذجة حالة تلك الواجهات. هذا يعني بدلاً من الخروج بخطوات لوصف المعاملات على الواجهات ، يقوم المطورون فقط بوصف الواجهات من حيث الحالة النهائية (مثل الوظيفة). عندما تحدث المعاملات لهذه الحالة ، تهتم React بتحديث واجهات المستخدم بناءً على ذلك.
  • React هي مجرد JavaScript ، وهناك واجهة برمجة تطبيقات صغيرة جدًا للتعلم ، فقط بعض الوظائف وكيفية استخدامها. بعد ذلك ، فإن مهاراتك في JavaScript هي التي تجعلك مطور React أفضل. لا توجد حواجز للدخول. يمكن لمطور JavaScript أن يصبح مطور React منتجًا في غضون ساعات قليلة.

ولكن هناك الكثير مما هو أكثر من ذلك. دعونا نحاول تغطية جميع الأسباب الكامنة وراء زيادة شعبية React. أحد الأسباب هو DOM الظاهري (خوارزمية تسوية React). سنعمل من خلال مثال لإظهار القيمة العملية الفعلية لامتلاك مثل هذه الخوارزمية تحت إمرتك.

ينص التعريف الرسمي لـ React على أنها مكتبة JavaScript لبناء واجهات المستخدم . من المهم فهم الجزأين المختلفين لهذا التعريف:

  1. React هي مكتبة JavaScript . إنه ليس إطار عمل. إنه ليس حلاً كاملاً وسنحتاج غالبًا إلى استخدام المزيد من المكتبات مع React لتشكيل أي حل. لا تفترض React أي شيء عن الأجزاء الأخرى في أي حل كامل. إنه يركز على شيء واحد فقط ، وعلى فعل ذلك الشيء بشكل جيد للغاية.
  2. الشيء الذي تقوم به React بشكل جيد هو الجزء الثاني من التعريف: بناء واجهات المستخدم . واجهة المستخدم هي أي شيء نضعه أمام المستخدمين لجعلهم يتفاعلون مع الجهاز. واجهات المستخدم في كل مكان ، من الأزرار البسيطة الموجودة في الميكروويف إلى لوحة أجهزة القياس في مكوك الفضاء. إذا كان الجهاز الذي نحاول واجهته يمكنه فهم JavaScript ، فيمكننا استخدام React لوصف واجهة المستخدم الخاصة به.

نظرًا لأن متصفحات الويب تفهم JavaScript ، يمكننا استخدام React لوصف واجهات مستخدم الويب. أحب استخدام الكلمة الموضحة هنا لأن هذا ما نفعله أساسًا مع React ، فنحن نقول له فقط ما نريده وسيقوم React ببناء واجهات المستخدم الفعلية نيابةً عنا في متصفح الويب. بدون React أو مكتبات مماثلة ، سنحتاج إلى إنشاء واجهات مستخدم يدويًا باستخدام واجهات برمجة تطبيقات الويب وجافا سكريبت.

عندما تسمع العبارة القائلة بأن "React تعريفية" ، فهذا بالضبط ما تعنيه ، فإننا نصف واجهات المستخدم بـ React ونخبرها بما نريد (وليس كيفية القيام بذلك). سيهتم React بـ "كيف" ويترجم أوصافنا التصريحية (التي نكتبها بلغة React) إلى واجهات مستخدم فعلية في المتصفح. تشارك React هذه القوة التصريحية البسيطة مع HTML نفسها ، ولكن مع React ، يمكننا أن نكون توضيحيين لواجهات HTML التي تمثل البيانات الديناميكية ، وليس البيانات الثابتة فقط.

لدى React ثلاثة مفاهيم تصميم رئيسية تدفع شعبيتها:

1 - استخدام المكونات القابلة لإعادة الاستخدام والتركيب وذات الحالة

في React ، نصف واجهات المستخدم باستخدام المكونات. يمكنك التفكير في المكونات على أنها وظائف بسيطة (في أي لغة برمجة). نسمي الدوال مع بعض المدخلات وتعطينا بعض المخرجات. يمكننا إعادة استخدام الوظائف حسب الحاجة وإنشاء وظائف أكبر من الوظائف الأصغر.

المكونات هي نفسها تمامًا ؛ نسمي مدخلاتهم "خصائص" و "الحالة" ، والمخرج المكون هو وصف لواجهة المستخدم (التي تشبه HTML للمتصفحات). يمكننا إعادة استخدام مكون واحد في العديد من واجهات المستخدم ، ويمكن أن تحتوي المكونات على مكونات أخرى.

على عكس الوظائف البحتة ، يمكن أن يكون لمكون React الكامل حالة خاصة للاحتفاظ بالبيانات التي قد تتغير بمرور الوقت.

2 - طبيعة التحديثات التفاعلية

اسم React هو التفسير البسيط لهذا المفهوم. عندما تتغير حالة المكون (المدخلات) ، تتغير أيضًا واجهة المستخدم التي يمثلها (المخرجات). يجب أن ينعكس هذا التغيير في وصف واجهة المستخدم في الجهاز الذي نعمل معه.

في المستعرض ، نحتاج إلى إعادة إنشاء طرق عرض HTML في نموذج كائن المستند (DOM). مع React ، لا داعي للقلق بشأن كيفية عكس هذه التغييرات ، أو حتى إدارة وقت إجراء التغييرات على المتصفح ؛ سوف تتفاعل React ببساطة مع تغييرات الحالة وتقوم تلقائيًا بتحديث DOM عند الحاجة.

3 - التمثيل الافتراضي للآراء في الذاكرة

باستخدام React ، نكتب HTML باستخدام JavaScript. نعتمد على قوة JavaScript لإنشاء HTML يعتمد على بعض البيانات ، بدلاً من تحسين HTML لجعلها تعمل مع تلك البيانات. تحسين HTML هو ما تفعله عادةً أطر JavaScript الأخرى. على سبيل المثال ، يقوم Angular بتوسيع HTML بميزات مثل الحلقات والشرطية وغيرها.

عندما نتلقى البيانات فقط من الخادم (في الخلفية ، مع AJAX) ، نحتاج إلى شيء أكثر من HTML للعمل مع تلك البيانات. إما باستخدام HTML محسّن ، أو باستخدام قوة JavaScript نفسها لإنشاء HTML. كلا النهجين لهما مزايا وعيوب. يتقبل React الأخير ، بحجة أن المزايا أقوى من العيوب.

في الواقع ، هناك ميزة رئيسية واحدة يمكن أن تثبت هذا النهج في حد ذاته ؛ إن استخدام JavaScript لتقديم HTML يجعل من السهل على React الاحتفاظ بتمثيل افتراضي لـ HTML في الذاكرة (والتي تُعرف عادةً باسم Virtual DOM ). تستخدم React نموذج DOM الظاهري لعرض شجرة HTML افتراضيًا أولاً ، وبعد ذلك ، في كل مرة تتغير فيها الحالة ونحصل على شجرة HTML جديدة يجب نقلها إلى DOM بالمتصفح ، بدلاً من كتابة الشجرة الجديدة بالكامل ، ستكتب React فقط الفرق بين الشجرة الجديدة والشجرة السابقة (نظرًا لأن React بها كلا الشجرتين في الذاكرة). تُعرف هذه العملية باسم Tree Reconciliation ، وأعتقد أنها أفضل شيء حدث في تطوير الويب منذ AJAX!

في المثال التالي ، سنركز على هذا المفهوم الأخير ونرى مثالًا عمليًا بسيطًا لعملية مصالحة الأشجار والفرق الكبير الذي تحدثه. سنكتب نفس مثال HTML مرتين ، أولاً باستخدام واجهات برمجة تطبيقات الويب الأصلية وجافا سكريبت الفانيليا ، ثم سنرى كيفية وصف شجرة HTML نفسها باستخدام React.

للتركيز فقط على هذا المفهوم الأخير ، لن نستخدم المكونات ، وسوف نسخر من عملية تغيير الحالة باستخدام مؤقت JavaScript. لن نستخدم JSX أيضًا ، على الرغم من أن استخدام JSX سيجعل رمزًا أبسط بكثير. أنا أستخدم JSX طوال الوقت عندما أكتب React ، لكن العمل مع React API مباشرة في هذا المثال سوف يجعلك تفهم هذا المفهوم بشكل أفضل.

مثال على خوارزمية التسوية في React

لمتابعة هذا المثال ، تحتاج إلى متصفح ومحرر كود. يمكنك في الواقع استخدام ملعب ترميز عبر الإنترنت ، لكنني سأستخدم الملفات المحلية واختبارها مباشرة في متصفح (لسنا بحاجة إلى خادم ويب):

سنبدأ هذا المثال من الصفر. قم بإنشاء دليل جديد ، وقم بتشغيل محررك المفضل هناك:

mkdir react-democd react-demoatom .

قم بإنشاء index.htmlملف في هذا الدليل ، ووضع قالب HTML قياسي فيه. قم بتضمين script.jsملف في هذا القالب ووضع console.logعبارة في هذا البرنامج النصي لاختبار ما إذا كان يعمل التضمين:

    React Demo     

افتح index.htmlالملف في المستعرض الخاص بك وتأكد من أنه يمكنك رؤية القالب الفارغ دون مشاكل ، وأنه يمكنك أن ترى في علامة التبويب أدوات تطوير وحدة التحكم console.logرسالة الاختبار التي وضعتها script.js:

open index.html # On Mac explorer index.html # On Windows

الآن ، دعنا نحضر مكتبة React نفسها ، والتي يمكننا تضمينها من موقع Reactjs. نسخ كل من reactو react-domمخطوطات، وتدرجها في index.html:

نقوم هنا بتضمين نصين مختلفين لسبب مهم: Reactيمكن استخدام المكتبة نفسها بدون متصفح. لاستخدام React مع متصفح ، نحتاج إلى ReactDOMالمكتبة.

عندما كنا تحديث المتصفح الآن، يجب أن نرى كلا Reactو ReactDOMمتوفرة على نطاق عالمي:

مع هذا الإعداد بسيطة، يمكننا الآن الوصول إلى كل من Reactو ReactDOMاجهات برمجة التطبيقات، وبالطبع، لدينا أيضا الوصول إلى واجهات برمجة التطبيقات الويب الأم وجافا سكريبت والتي نحن بصدد استخدام أولا.

لإدخال HTML ديناميكيًا في المتصفح ، يمكننا ببساطة استخدام JavaScript خالص و DOM Web API نفسها. لنقم بإنشاء divعنصر لاستضافة محتوى JavaScript HTML الخاص بنا ومنحه المعرف "js". في عنصر النص الأساسي index.html، قبل scriptالعلامة مباشرةً ، أضف:

الآن script.js، لنأخذ هذا divالعنصر الجديد بمعرفه ونضعه في ثابت. دعونا نسمي هذا الثابت jsContainer. يمكننا استخدامها document.getElementByIdللحصول على divمن HTML:

jsContainer.innerHTML = ` Hello JS `;

للتحكم في محتوى هذا div، يمكننا استخدام innerHTMLاستدعاء setter على divالعنصر مباشرة. يمكننا استخدام هذا الاستدعاء لتوفير أي قالب HTML نريد إدراجه في DOM. دعنا ندرج divعنصرًا بفئة "demo" والسلسلة "Hello JS" كمحتواه:

jsContainer.innerHTML = ` Hello JS `;ReactDOM.render( /* TODO: React's version of the HTML template */, reactContainer )

Make sure this works in the browser. You should see the “Hello JS” line on the screen now.

This demo div is our User Interface so far. It’s a very simple one. We just output a text for the user to see.

Both document.getElementById and element.innerHTML are actually part of the native DOM Web API. We are communicating with the browser directly here using the supported APIs of the Web platform. When we write React code, however, we use the React API instead, and we let React communicate with the browser using the DOM Web API.

React acts like our agent for the browser, and we mostly need to communicate with just React, our agent, and not the browser itself. I say mostly because there are cases where we still need to communicate with the browser, but those are rare.

To create the exact same User Interface that we have so far but with React API this time, let’s create another div element and give it an id of "react". In index.html, right under the div#js element, add:

Now, in script.js, create a new container constant for the new div:

const reactContainer = document.getElementById("react");

This container will be the only call we make to the native web API. ReactDOM needs this container to know where to host our application in the DOM.

With the react container identified, we can now use the ReactDOM library to render React's version of the HTML template to this container:

ReactDOM.render( /* TODO: React's version of the HTML template */, reactContainer )

What we’re going to do next is your first milestone in truly understanding the React library. Remember when I told you that with React we write HTML using JavaScript? This is exactly what we are going to do next.

To write our simple HTML User Interface, we are going to use JavaScript calls to React API, and by the end of the example you’ll have a better picture about the reason for doing so.

Instead of working with strings (as we did in the native JavaScript example above), in React, we work with objects. Any HTML string will be represented as an object using a React.createElement call (which is the core function in the React API).

Here’s the equivalent HTML User Interface we have so far with React:

ReactDOM.render( React.createElement( "div", { className: "demo" }, "Hello React" ), reactContainer );

React.createElement has many arguments:

  • The first argument is the HTML tag, which is div in our example.
  • The second argument is an object that represents any attributes we want this tag to have. To match the native JS example we used { className: "demo" } which translates to class="demo". Note how we used className instead of class in the attributes because with React it's all JavaScript that matches the Web API, not HTML itself.
  • The third argument is the content of the element. We’ve put a “Hello React” string in there.

We can test this now. The browser should render both “Hello JS” and “Hello React”. Let’s style the demo divs as a box, using this CSS, just so that we can visually split the screen. In index.html:

 .demo { border: 1px solid #ccc; margin: 1em; padding: 1em; } 

We now have two nodes, one being controlled with the DOM Web API directly, and another being controlled with the React API (which in turn uses the DOM Web API). The only major difference between the ways we are building these two nodes in the browser is that in the JS version we used a string to represent the content, while in the React version we used pure JavaScript calls and represented the content with an object instead of a string.

No matter how complicated the HTML User Interface is going to get, when using React, every HTML element will be represented with a JavaScript object using a React.createElement call.

Let’s now add some more features to our simple User Interface. Let’s add a text box to read input from the user.

To nest elements in our HTML template, it’s straight forward in the JS version because it’s just HTML. For example, to make the demo div render an element, we simply add it to the content:

jsContainer.innerHTML = ` Hello JS `;

We can do the same with React by adding more arguments after the 3rd argument for React.createElement. To match what we did in the native JS example, we can add a 4th argument that is another React.createElement call that renders an input element (remember, every HTML element is an object):

ReactDOM.render( React.createElement( "div", { className: "demo" }, "Hello React", React.createElement("input") ), reactContainer );

At this point, if you’re questioning what we’re doing and thinking “this is complicating a simple process”, you are totally right! But there is a very good reason for what we’re doing. Keep reading.

Let’s also render a timestamp in both versions. In the JS version, let’s put the timestamp in a paragraph element. We can use a call to new Date() to display a simple timestamp:

jsContainer.innerHTML = ` Hello JS  

${new Date()}

`;

To do the same in React, we add a 5th argument to the top-level div element. This new 5th argument is another React.createElement call, this time using a p tag, with no attributes, and the new Date() string for content:

ReactDOM.render( React.createElement( "div", { className: "demo" }, "Hello React", React.createElement("input"), React.createElement( "p", null, new Date().toString() ) ), reactContainer );

Both JS and React versions are still rendering the exact same HTML in the browser.

As you can see, so far, using React is actually a lot harder than the simple and familiar native way. What is it that React does so well that’s worth giving up the familiar HTML and having to learn a new API to write what can be simply written in HTML? The answer is not about rendering the first HTML view, it’s about what we need to do to update any existing view in the DOM.

So, let’s do an update operation on the DOM we have so far. Let’s simply make the timestamp tick every second.

We can easily repeat a JavaScript function call in a browser using the setInterval Web timer API. So, let's put all of our DOM manipulations for both JS and React versions in a function, call it render, and use it in a setInterval call to make it repeat every second.

Here’s the full final code in script.js:

const jsContainer = document.getElementById("js"); const reactContainer = document.getElementById("react"); const render = () => { jsContainer.innerHTML = ` Hello JS  

${new Date()}

`; ReactDOM.render( React.createElement( "div", { className: "demo" }, "Hello React ", React.createElement("input"), React.createElement( "p", null, new Date().toString() ) ), reactContainer ); } setInterval(render, 1000);

When we refresh the browser now, the timestamp string should be ticking every second in both versions. We are now updating our User Interface in the DOM.

This is the moment when React will potentially blow your mind. If you try to type something in the text box of the JS version, you won’t be able to. This is very much expected because we’re basically throwing away the whole DOM node on every tick and regenerating it. However, if you try to type something in the text box that’s rendered with React, you can certainly do so!

Although the whole React rendering code is within our ticking timer, React is changing only the timestamp paragraph and not the whole DOM node. This is why the text input box was not regenerated and we were able to type in it.

You can see the different ways we’re updating the DOM visually if you inspect the two DOM nodes in a Chrome dev tools elements panel. The Chrome div tools highlights any HTML elements that get updated. You’ll see how we are regenerating the whole “js” div on every tick, while React is smartly only regenerating the paragraph with the timestamp string.

React has a smart diffing algorithm that it uses to only regenerate in its DOM node what actually needs to be regenerated while it keeps everything else as is. This diffing process is possible because of React’s virtual DOM and the fact that we have a representation of our User Interface in memory (because we wrote in JavaScript).

Using the virtual DOM, React keeps the last DOM version in memory and when it has a new DOM version to take to the browser, that new DOM version will also be in memory, so React can compute the difference between the new and the old versions (in our case, the difference is the timestamp paragraph).

React will then instruct the browser to update only the computed diff and not the whole DOM node. No matter how many times we regenerate our interface, React will take to the browser only the new “partial” updates.

لا تعتبر هذه الطريقة أكثر فاعلية فحسب ، ولكنها تزيل أيضًا طبقة كبيرة من التعقيد للطريقة التي نفكر بها في تحديث واجهات المستخدم. إن قيام React بإجراء جميع العمليات الحسابية حول ما إذا كان يجب علينا تحديث DOM أم لا يمكننا من التركيز على التفكير في بياناتنا (الحالة) وطريقة وصف واجهة المستخدم الخاصة بها.

نقوم بعد ذلك بإدارة التحديثات على بياناتنا حسب الحاجة دون القلق بشأن الخطوات اللازمة لعكس هذه التحديثات على واجهة المستخدم الفعلية في المتصفح (لأننا نعلم أن React ستفعل ذلك بالضبط وستقوم بذلك بطريقة فعالة!)

شكرا للقراءة! يمكنك مشاهدة الكود المصدري للعرض التوضيحي الخاص بي هنا ، ويمكنك مشاهدة العرض قيد التشغيل هنا.

تعلم React أو Node؟ تحقق من كتبي:

  • تعلم React.js عن طريق إنشاء الألعاب
  • Node.js ما وراء الأساسيات