التوجيه العالمي لتطبيقات التفاعل

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

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

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

هل التوجيه ضروري؟


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

لذلك ، بالنسبة لتطبيق صفحة واحدة ، يجب دائمًا أن يكون تغيير المكونات وتغيير الحالة الداخلية للتطبيق مصحوبًا بتغيير في عنوان url.

لماذا التوجيه هكذا؟


وظيفة التوجيه في الأطر الشائعة لتطبيقات الويب الأمامية ، في رأيي ، تتأثر باتصالها التاريخي بالتوجيه في تطبيقات الويب الكلاسيكية (مع تقديم الخادم).

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

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

ماذا تقدم مكتبة الموجه العالمي؟


تقدم مكتبة الموجه العالمي تجاهل كل ما هو غير ضروري وترك هذا الجزء الذي يمكن استخدامه مع أو بدون أي إطار عمل عند تقديمه على كلٍ من العميل وعلى جانب خادم الويب (في تطبيقات الويب العالمية / المتشابهة).

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

import React from 'react'; import UniversalRouter from 'universal-router'; import App from './App'; import Link from './Link'; const routes = { path: '/', async action({next}) { const children = await next(); return ( <App> {children} </App> ); }, children: [ { path: '', async action() { return ( <div>Root route go to <Link href='/test'>Test</Link></div> ); }, }, { path: '/test', async action({next}) { const children = await next(); return ( <App> {children} </App> ); }, children: [ { path: '', async action() { return ( <div>Test route return to <Link href='/'>Root</Link></div> ); }, }, ] }, ], }; export const basename = ''; const router = new UniversalRouter(routes, { baseUrl: basename }); export default router; 

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

وكيف يعمل هذا مع React؟


حدد طريقة التنقل () للتاريخ ، على الرغم من أنه في كثير من الحالات ، يكفي استخدام طريقة الدفع الأصلية ()

 import { createBrowserHistory } from 'history' import parse from 'url-parse' import deepEqual from 'deep-equal' const isNode = new Function('try {return this===global;}catch(e){return false;}') //eslint-disable-line let history if (!isNode()) { history = createBrowserHistory() history.navigate = function (path, state) { const parsedPath = parse(path) const location = history.location if (parsedPath.pathname === location.pathname && parsedPath.query === location.search && parsedPath.hash === location.hash && deepEqual(state, location.state)) { return } const args = Array.from(arguments) args.splice(0, 2) return history.push(...[path, state, ...args]) } } else { history = {} history.navigate = function () {} } export default history 

نقوم أيضًا بإنشاء مكون Link الذي سيؤدي إلى تشغيل التنقل:

 import React from 'react'; import {basename} from './router'; import history from './history'; function noOp(){}; const createOnClickAnchor = (callback) => { return (e) => { e.preventDefault(); history.navigate(e.currentTarget.getAttribute('href')); callback(e); }; }; export default ({href, onClick = noOp, children, ...rest}) => ( <a href={basename + href} onClick={createOnClickAnchor(onClick)} {...rest} > {children} </a> ); 

أنت الآن جاهز لتقديم المكون:

 import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import * as serviceWorker from './serviceWorker'; import history from './history'; import router from './router'; const render = async (location) => { const element = await router.resolve(location); ReactDOM.render( element, document.getElementById('root'), ); }; render(history.location); history.listen(render); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA serviceWorker.unregister(); 

رمز المشروع

روابط مفيدة

1. medium.com/@ippei.tanaka/universal-router-history-react-97ec79464573

Source: https://habr.com/ru/post/ar484514/


All Articles