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

كيف بدأ كل شيء
في الآونة الأخيرة ، ألهمني
موكلي لمعرفة المزيد عن استخدام
RxJS لإدارة حالة تطبيقات
React . عندما قمت بتدقيق رمز التطبيق لهذا العميل ، أراد أن يعرف رأيي حول كيفية تطويره للتطبيق ، بالنظر إلى أنه قبل ذلك كان يستخدم حصريًا الحالة المحلية لـ React. وصل المشروع إلى نقطة حيث كان من غير المعقول الاعتماد فقط على رد الفعل. أولاً ، تحدثنا عن استخدام
Redux أو MobX كوسيلة أفضل لإدارة حالة تطبيقك. أنشأ عميلي نموذجًا أوليًا لكل من هذه التقنيات. لكنه لم يتوقف عند هذه التقنيات ، وخلق نموذج أولي لتطبيق React يستخدم RxJS. منذ تلك اللحظة ، أصبحت محادثتنا أكثر إثارة للاهتمام.
كان التطبيق المعني عبارة عن منصة تداول للعملات المشفرة. كان لديه العديد من الحاجيات التي تم تحديث بياناتها في الوقت الحقيقي. كان على مطوري هذا التطبيق ، من بين آخرين ، حل المهام الصعبة التالية:
- إدارة طلبات بيانات متعددة (غير متزامنة).
- تحديث في الوقت الحقيقي لعدد كبير من الحاجيات على لوحة التحكم.
- الحل لمشكلة الحاجيات واتصال البيانات ، حيث أن بعض الحاجيات تحتاج إلى البيانات ليس فقط من بعض المصادر الخاصة ، ولكن أيضًا من الحاجيات الأخرى.
ونتيجة لذلك ، لم تكن الصعوبات الرئيسية التي واجهها المطورون مرتبطة بمكتبة React نفسها ، وبالإضافة إلى ذلك ، يمكنني مساعدتهم في هذا المجال. كانت المشكلة الرئيسية هي جعل الآليات الداخلية للنظام تعمل بشكل صحيح ، تلك التي ربطت بيانات العملة المشفرة وعناصر الواجهة التي تم إنشاؤها بواسطة أدوات التفاعل. في هذا المجال ، كانت قدرات RxJS في متناول اليدين ، وكان النموذج الأولي الذي أظهروه لي واعدًا للغاية.
باستخدام RxJS في رد الفعل
لنفترض أن لدينا تطبيقًا ، بعد تنفيذ بعض الإجراءات المحلية ، يقدم طلبات
لواجهة برمجة تطبيقات تابعة لجهة خارجية . يسمح لك بالبحث حسب المادة. قبل تنفيذ الطلب ، نحتاج إلى الحصول على النص المستخدم لتكوين هذا الطلب. على وجه الخصوص ، نحن ، باستخدام هذا النص ، نشكل عنوان URL للوصول إلى API. إليك رمز مكون React الذي يقوم بتنفيذ هذه الوظيفة
import React from 'react'; const App = ({ query, onChangeQuery }) => ( <div> <h1>React with RxJS</h1> <input type="text" value={query} onChange={event => onChangeQuery(event.target.value)} /> <p>{`http://hn.algolia.com/api/v1/search?query=${query}`}</p> </div> ); export default App;
هذا المكون يفتقر إلى نظام إدارة الدولة. لا يتم تخزين حالة خاصية
query
أي مكان ، ولا تقوم وظيفة
onChangeQuery
أيضًا بتحديث الحالة. في النهج التقليدي ، تم تجهيز هذا المكون بنظام إدارة الدولة المحلية. يبدو هذا:
class App extends React.Component { constructor(props) { super(props); this.state = { query: '', }; } onChangeQuery = query => { this.setState({ query }); }; render() { return ( <div> <h1>React with RxJS</h1> <input type="text" value={this.state.query} onChange={event => this.onChangeQuery(event.target.value) } /> <p>{`http:
ومع ذلك ، ليس هذا هو النهج الذي سنتحدث عنه هنا. بدلاً من ذلك ، نريد إنشاء نظام إدارة حالة تطبيق باستخدام RxJS. دعنا نلقي نظرة على كيفية القيام بذلك باستخدام مكون الترتيب العالي (HOC).
إذا كنت ترغب في ذلك ، يمكنك تنفيذ منطق مماثل في مكون
App
الخاص بك ، ولكنك على الأرجح ، في مرحلة ما من عملك على التطبيق ، تقرر تصميم مثل هذا المكون في شكل
HOC مناسب لإعادة الاستخدام.
تفاعل و RxJS مكونات النظام الأعلى
سنكتشف كيفية إدارة حالة تطبيقات React باستخدام RxJS ، باستخدام مكون ترتيب أعلى لهذا الغرض. بدلاً من ذلك ، يمكن للمرء تنفيذ
نموذج الدعائم تقديم. ونتيجة لذلك ، إذا كنت لا ترغب في إنشاء مكون ترتيب أعلى لهذا الغرض بنفسك ، يمكنك استخدام مكونات الترتيب الأعلى القابلة للملاحظة مع
إعادة mapPropsStream()
مع
mapPropsStream()
componentFromStream()
. في هذا الدليل ، ومع ذلك ، سنفعل كل شيء بمفردنا.
import React from 'react'; const withObservableStream = (...) => Component => { return class extends React.Component { componentDidMount() {} componentWillUnmount() {} render() { return ( <Component {...this.props} {...this.state} /> ); } }; }; const App = ({ query, onChangeQuery }) => ( <div> <h1>React with RxJS</h1> <input type="text" value={query} onChange={event => onChangeQuery(event.target.value)} /> <p>{`http://hn.algolia.com/api/v1/search?query=${query}`}</p> </div> ); export default withObservableStream(...)(App);
بينما لا يقوم مكون RxJS الأعلى رتبة بأي إجراءات. تقوم فقط بنقل حالتها وخصائصها إلى مكون الإدخال ، والذي من المقرر توسيعه بمساعدته. كما ترون ، في النهاية ، سيشارك عنصر عالي الترتيب في إدارة حالة التفاعل. ومع ذلك ، سيتم الحصول على هذه الحالة من التدفق المرصود. قبل البدء في تنفيذ HOC واستخدامه مع مكون
App
، نحتاج إلى تثبيت RxJS:
npm install rxjs
لنبدأ الآن في استخدام مكون ترتيب أعلى وتنفيذ منطقه:
import React from 'react'; import { BehaviorSubject } from 'rxjs'; ... const App = ({ query, onChangeQuery }) => ( <div> <h1>React with RxJS</h1> <input type="text" value={query} onChange={event => onChangeQuery(event.target.value)} /> <p>{`http://hn.algolia.com/api/v1/search?query=${query}`}</p> </div> ); const query$ = new BehaviorSubject({ query: 'react' }); export default withObservableStream( query$, { onChangeQuery: value => query$.next({ query: value }), } )(App);
لا يتغير مكون
App
نفسه. لقد مررنا للتو حجتين إلى مكون ترتيب أعلى. نصفهم:
- كائن مرصود. وسيطة
query
هي كائن يمكن ملاحظته وله قيمة أولية ، ولكنه بالإضافة إلى ذلك ، يُرجع ، بمرور الوقت ، قيمًا جديدة (نظرًا لأن هذا هو BehaviorSubject
). يمكن لأي شخص الاشتراك في هذا الكائن يمكن ملاحظته. إليك ما تقوله وثائق RxJS عن كائنات من النوع BehaviorSubject
: "أحد الخيارات لكائنات Subject
هو كائن BehaviorSubject
يستخدم مفهوم" القيمة الحالية ". يقوم بتخزين آخر قيمة تم تمريرها إلى المشتركين فيه ، وعندما يشترك فيها مراقب جديد ، يتلقى على الفور هذه "القيمة الحالية" من BehaviorSubject
. هذه الأشياء مناسبة تمامًا لتقديم البيانات ، والتي تظهر أجزاء جديدة منها بمرور الوقت ". - نظام إصدار القيم الجديدة للكائن المرصود (المشغل). دالة
onChangeQuery()
، التي تم تمريرها من خلال HOC إلى مكون App
، هي وظيفة عادية تقوم بتمرير القيمة التالية إلى الكائن المرصود. يتم نقل هذه الوظيفة في الكائن ، حيث قد يكون من الضروري الانتقال إلى مكون أعلى رتبة عدة وظائف تؤدي إجراءات معينة مع الكائنات المرصودة.
بعد إنشاء الكائن المرصود والاشتراك فيه ، يجب أن يعمل تدفق الطلب. ومع ذلك ، حتى الآن ، يبدو عنصر النظام الأعلى نفسه بمثابة صندوق أسود بالنسبة لنا. ندرك ذلك:
const withObservableStream = (observable, triggers) => Component => { return class extends React.Component { componentDidMount() { this.subscription = observable.subscribe(newState => this.setState({ ...newState }), ); } componentWillUnmount() { this.subscription.unsubscribe(); } render() { return ( <Component {...this.props} {...this.state} {...triggers} /> ); } }; };
يتلقى المكون ذو الترتيب الأعلى كائنًا يمكن ملاحظته وكائن به مشغلات (ربما يمكن تسمية هذا الكائن الذي يحتوي على وظائف بمصطلح أكثر نجاحًا من معجم RxJS) ، ممثلة في توقيع الوظيفة.
يتم تمرير المشغلات فقط من خلال HOC إلى مكون الإدخال. هذا هو السبب في أن مكون
App
يتلقى مباشرة وظيفة
onChangeQuery()
، والتي تعمل مباشرة مع الكائن المرصود ، وتمرير قيم جديدة إليه.
يستخدم الكائن الذي تمت ملاحظته طريقة دورة حياة ComponDidMount
componentDidMount()
للتوقيع وطريقة
componentDidMount()
لإلغاء الاشتراك. مطلوب إلغاء الاشتراك لمنع
تسرب الذاكرة . في اشتراك الكائن المرصود ، ترسل الوظيفة فقط جميع البيانات الواردة من الدفق إلى مخزن حالة
this.setState()
المحلي باستخدام الأمر
this.setState()
.
دعنا نجري تغييرًا
App
مكون
App
، والذي سيتخلص من المشكلة التي تحدث إذا لم يقم المكون ذو الترتيب الأعلى بتعيين القيمة الأولية لخاصية
query
. إذا لم يتم ذلك ، فسيتم إلغاء تحديد خاصية
query
في بداية العمل. بفضل هذا التغيير ، تحصل هذه الخاصية على القيمة الافتراضية.
const App = ({ query = '', onChangeQuery }) => ( <div> <h1>React with RxJS</h1> <input type="text" value={query} onChange={event => onChangeQuery(event.target.value)} /> <p>{`http://hn.algolia.com/api/v1/search?query=${query}`}</p> </div> );
هناك طريقة أخرى للتعامل مع هذه المشكلة وهي تعيين الحالة الأولية
query
في مكون ترتيب أعلى:
const withObservableStream = ( observable, triggers, initialState, ) => Component => { return class extends React.Component { constructor(props) { super(props); this.state = { ...initialState, }; } componentDidMount() { this.subscription = observable.subscribe(newState => this.setState({ ...newState }), ); } componentWillUnmount() { this.subscription.unsubscribe(); } render() { return ( <Component {...this.props} {...this.state} {...triggers} /> ); } }; }; const App = ({ query, onChangeQuery }) => ( ... ); export default withObservableStream( query$, { onChangeQuery: value => query$.next({ query: value }), }, { query: '', } )(App);
إذا حاولت هذا التطبيق الآن ، يجب أن يعمل مربع الإدخال كما هو متوقع. يتلقى مكون
App
من HOC ، في شكل خصائص ، فقط حالة
query
والدالة
onChangeQuery
لتغيير الحالة.
يحدث الاسترداد وتغيير الحالة من خلال كائنات RxJS التي يمكن ملاحظتها ، على الرغم من حقيقة أنه يتم استخدام مخزن حالة تفاعل داخلي داخل المكون ذي الترتيب الأعلى. لم أتمكن من العثور على حل واضح لمشكلة تدفق البيانات من اشتراك الكائنات المرصودة مباشرة إلى خصائص المكون الموسع (
App
). هذا هو السبب في أنني اضطررت إلى استخدام حالة التفاعل المحلية في شكل طبقة وسيطة ، والتي ، بالإضافة إلى ذلك ، مريحة من حيث أسباب إعادة التقديم. إذا كنت تعرف طريقة أخرى لتحقيق نفس الأهداف - يمكنك مشاركتها في التعليقات.
الجمع بين الأجسام المرصودة في رد الفعل
دعنا ننشئ دفقًا ثانيًا من القيم ، والتي ، مثل خاصية
query
، يمكن استخدامها في مكون
App
. سنستخدم لاحقًا كلتا القيمتين ، ونعمل معهم باستخدام كائن آخر يمكن ملاحظته.
const SUBJECT = { POPULARITY: 'search', DATE: 'search_by_date', }; const App = ({ query = '', subject, onChangeQuery, onSelectSubject, }) => ( <div> <h1>React with RxJS</h1> <input type="text" value={query} onChange={event => onChangeQuery(event.target.value)} /> <div> {Object.values(SUBJECT).map(value => ( <button key={value} onClick={() => onSelectSubject(value)} type="button" > {value} </button> ))} </div> <p>{`http://hn.algolia.com/api/v1/${subject}?query=${query}`}</p> </div> );
كما ترى ، يمكن استخدام معلمة
subject
لتحسين الطلب عند إنشاء URL المستخدم للوصول إلى API. وبالتحديد ، يمكن البحث عن المواد بناءً على شعبيتها أو في تاريخ النشر. بعد ذلك ، قم بإنشاء كائن آخر يمكن ملاحظته يمكن استخدامه لتغيير معلمة
subject
. يمكن استخدام هذا الملاحظة لربط مكون
App
مع مكون ترتيب أعلى. خلاف ذلك ، لن تعمل الخصائص التي تم تمريرها إلى مكون
App
.
import React from 'react'; import { BehaviorSubject, combineLatest } from 'rxjs/index'; ... const query$ = new BehaviorSubject({ query: 'react' }); const subject$ = new BehaviorSubject(SUBJECT.POPULARITY); export default withObservableStream( combineLatest(subject$, query$, (subject, query) => ({ subject, query, })), { onChangeQuery: value => query$.next({ query: value }), onSelectSubject: subject => subject$.next(subject), }, )(App);
onSelectSubject()
ليس جديدا. يمكن استخدامه ، من خلال زر ، للتبديل بين حالتي
subject
. لكن الشيء المرصود الذي تم نقله إلى مكون أعلى رتبة هو شيء جديد. يستخدم الدالة
combineLatest()
من RxJS لدمج آخر القيم التي تم إرجاعها من اثنين (أو أكثر) من التدفقات المرصودة. بعد الاشتراك في الكائن المرصود ، إذا تم تغيير أي من القيم (
query
أو
subject
) ، فإن المشترك سيحصل على كلتا القيمتين.
تكملة الآلية التي
combineLatest()
الدالة
combineLatest()
هي
combineLatest()
الأخير. هنا يمكنك تعيين ترتيب الإرجاع للقيم التي تم إنشاؤها بواسطة الكائنات المرصودة. في حالتنا ، نحتاج إلى تمثيلهم كشيء. سيسمح هذا ، كما كان من قبل ، بتدميرها في مكون عالي المستوى وكتابتها إلى حالة رد الفعل المحلية. نظرًا لأن لدينا بالفعل البنية اللازمة ، يمكننا حذف خطوة التفاف كائن كائن
query
المرصود.
... const query$ = new BehaviorSubject('react'); const subject$ = new BehaviorSubject(SUBJECT.POPULARITY); export default withObservableStream( combineLatest(subject$, query$, (subject, query) => ({ subject, query, })), { onChangeQuery: value => query$.next(value), onSelectSubject: subject => subject$.next(subject), }, )(App);
الكائن المصدر ،
{ query: '', subject: 'search' }
، بالإضافة إلى جميع الكائنات الأخرى التي يتم إرجاعها بواسطة الدفق المجمع للكائنات المرصودة ، مناسبة لتدميرها في مكون عالي الترتيب وللكتابة القيم المقابلة لحالة التفاعل المحلية. بعد تحديث الحالة ، كما كان من قبل ، يتم إجراء التقديم. عند تشغيل التطبيق المحدث ، يجب أن تكون قادرًا على تغيير القيمتين باستخدام حقل الإدخال والزر. تؤثر القيم التي تم تغييرها على عنوان URL المستخدم للوصول إلى API. حتى إذا تغيرت واحدة فقط من هذه القيم ، فإن القيمة الأخرى تحتفظ بحالتها الأخيرة ، حيث إن
combineLatest()
تجمع دائمًا بين أحدث القيم الصادرة من التدفقات المرصودة.
Axios و RxJS في رد الفعل
الآن في نظامنا ، تم إنشاء عنوان URL للوصول إلى واجهة برمجة التطبيقات استنادًا إلى قيمتين من كائن يمكن ملاحظتهما ، والذي يتضمن كائنين آخرين يمكن ملاحظتهما. في هذا القسم ، سنستخدم عنوان URL لتحميل البيانات من واجهة برمجة التطبيقات. قد تكون قادرًا على استخدام
نظام تحميل البيانات المتفاعل ، ولكن عند استخدام كائنات RxJS القابلة للملاحظة ، تحتاج إلى إضافة دفق آخر يمكن ملاحظته إلى تطبيقنا.
قبل أن نبدأ العمل على الكائن الملاحظ التالي ، قم بتثبيت
المحاور . هذه هي المكتبة التي سنستخدمها لتحميل البيانات من التدفقات إلى البرنامج.
npm install axios
تخيل الآن أن لدينا مجموعة من المقالات التي يجب أن
App
مكون
App
. هنا ، كقيمة المعلمة الافتراضية المقابلة ، نستخدم صفيفًا فارغًا ، ونفعل الشيء نفسه كما فعلنا مع المعلمات الأخرى.
... const App = ({ query = '', subject, stories = [], onChangeQuery, onSelectSubject, }) => ( <div> ... <p>{`http://hn.algolia.com/api/v1/${subject}?query=${query}`}</p> <ul> {stories.map(story => ( <li key={story.objectID}> <a href={story.url || story.story_url}> {story.title || story.story_title} </a> </li> ))} </ul> </div> );
بالنسبة لكل مقالة في القائمة ، يتم استخدام قيمة احتياطي نظرًا لأن واجهة برمجة التطبيقات التي نصل إليها ليست موحدة. الآن - الأكثر إثارة للاهتمام - تنفيذ كائن جديد يمكن ملاحظته وهو مسؤول عن تحميل البيانات في تطبيق React الذي سيصورها.
import React from 'react'; import axios from 'axios'; import { BehaviorSubject, combineLatest } from 'rxjs'; import { flatMap, map } from 'rxjs/operators'; ... const query$ = new BehaviorSubject('react'); const subject$ = new BehaviorSubject(SUBJECT.POPULARITY); const fetch$ = combineLatest(subject$, query$).pipe( flatMap(([subject, query]) => axios(`http://hn.algolia.com/api/v1/${subject}?query=${query}`), ), map(result => result.data.hits), ); ...
كائن جديد يمكن ملاحظته هو ، مرة أخرى ، مزيجًا من ملاحظات
subject
query
، نظرًا لأنه لإنشاء عنوان URL الذي سنصل به إلى واجهة برمجة التطبيقات لتحميل البيانات ، نحتاج إلى كلتا القيمتين. في طريقة
pipe()
للكائن المرصود ، يمكننا استخدام ما يسمى "عوامل تشغيل RxJS" من أجل تنفيذ إجراءات معينة بالقيم. في هذه الحالة ، نقوم بتعيين قيمتين تم وضعها في الاستعلام ، والتي تستخدمها المحاور للحصول على النتيجة. هنا نستخدم
flatMap()
وليس
map()
للوصول إلى نتيجة الوعد الذي تم حله بنجاح ، وليس إلى الوعد الذي تم إرجاعه نفسه. ونتيجة لذلك ، بعد الاشتراك في هذا الكائن الجديد المرصود ، في كل مرة يتم فيها إدخال
subject
أو قيمة
query
جديدة في النظام من كائنات مرصودة أخرى ، يتم تنفيذ
query
جديد وتكون النتيجة في وظيفة الاشتراك.
الآن ، مرة أخرى ، يمكننا تقديم عنصر جديد يمكن ملاحظته لمكون عالي الترتيب. لدينا الحجة الأخيرة
combineLatest()
بين
combineLatest()
تحت تصرفنا ، وهذا يجعل من الممكن
combineLatest()
مباشرة إلى خاصية تسمى
stories
. في النهاية ، يمثل هذا كيفية استخدام هذه البيانات بالفعل في مكون
App
.
export default withObservableStream( combineLatest( subject$, query$, fetch$, (subject, query, stories) => ({ subject, query, stories, }), ), { onChangeQuery: value => query$.next(value), onSelectSubject: subject => subject$.next(subject), }, )(App)
لا يوجد زناد هنا ، حيث يتم تنشيط الكائن المرصود بشكل غير مباشر من خلال تدفقين آخرين ملاحظين. في كل مرة يتم فيها تغيير القيمة في حقل الإدخال (
query
) أو النقر فوق الزر (
subject
) ، يؤثر هذا على كائن
fetch
تمت ملاحظته ، والذي يحتوي على أحدث القيم من كلا التدفقين.
ومع ذلك ، ربما لا نحتاج إلى أنه في كل مرة نغير فيها القيمة في حقل الإدخال ، سيؤثر ذلك على كائن
fetch
الملاحظ. بالإضافة إلى ذلك ، لا نريد أن يتأثر
fetch
إذا كانت القيمة عبارة عن سلسلة فارغة. هذا هو السبب في أننا يمكن أن نوسع كائن
query
القابل للرصد باستخدام عبارة
debounce
، التي تقضي على تغييرات الاستعلام المتكررة. وبالتحديد بفضل هذه الآلية ، لا يتم قبول حدث جديد إلا بعد وقت محدد مسبقًا بعد الحدث السابق. بالإضافة إلى ذلك ، نستخدم
filter
هنا ، الذي يقوم بتصفية أحداث الدفق إذا كانت سلسلة
query
فارغة.
import React from 'react'; import axios from 'axios'; import { BehaviorSubject, combineLatest, timer } from 'rxjs'; import { flatMap, map, debounce, filter } from 'rxjs/operators'; ... const queryForFetch$ = query$.pipe( debounce(() => timer(1000)), filter(query => query !== ''), ); const fetch$ = combineLatest(subject$, queryForFetch$).pipe( flatMap(([subject, query]) => axios(`http://hn.algolia.com/api/v1/${subject}?query=${query}`), ), map(result => result.data.hits), ); ...
يقوم بيان
debounce
بعمل إدخال البيانات في الحقل. ومع ذلك ، عندما ينقر زر على قيمة
subject
، يجب تنفيذ الطلب على الفور.
الآن ، القيم الأولية
query
subject
، والتي نراها عند عرض مكون
App
لأول مرة ، ليست هي نفسها التي تم الحصول عليها من القيم الأولية للكائنات المرصودة:
const query$ = new BehaviorSubject('react'); const subject$ = new BehaviorSubject(SUBJECT.POPULARITY);
subject
مكتوب في
subject
، سلسلة فارغة في
query
. ويرجع ذلك إلى حقيقة أن هذه القيم هي التي قدمناها كمعلمات افتراضية لإعادة هيكلة وظيفة مكون
App
في التوقيع. والسبب في ذلك هو أننا بحاجة إلى انتظار الطلب الأولي الذي ينفذه كائن
fetch
المرصود. نظرًا لأنني لا أعرف بالضبط كيفية الحصول على القيم على الفور من
query
يمكن ملاحظتها وكائنات
subject
في مكون ترتيب أعلى من أجل كتابتها إلى حالة محلية ، فقد قررت إعداد الحالة الأولية لمكون الترتيب الأعلى مرة أخرى.
const withObservableStream = ( observable, triggers, initialState, ) => Component => { return class extends React.Component { constructor(props) { super(props); this.state = { ...initialState, }; } componentDidMount() { this.subscription = observable.subscribe(newState => this.setState({ ...newState }), ); } componentWillUnmount() { this.subscription.unsubscribe(); } render() { return ( <Component {...this.props} {...this.state} {...triggers} /> ); } }; };
الآن يمكن توفير الحالة الأولية لمكون عالي الترتيب كوسيطة ثالثة. في المستقبل ، يمكننا إزالة الإعدادات الافتراضية لمكون
App
.
... const App = ({ query, subject, stories, onChangeQuery, onSelectSubject, }) => ( ... ); export default withObservableStream( combineLatest( subject$, query$, fetch$, (subject, query, stories) => ({ subject, query, stories, }), ), { onSelectSubject: subject => subject$.next(subject), onChangeQuery: value => query$.next(value), }, { query: 'react', subject: SUBJECT.POPULARITY, stories: [], }, )(App);
ما يقلقني الآن هو أن الحالة الأولية قد تم تعيينها أيضًا في إعلان
query$
الكائنات المرصودة
query$
subject$
. هذا النهج عرضة للخطأ ، حيث أن تهيئة الكائنات المرصودة والحالة الأولية لمكون الترتيب الأعلى تشترك في نفس القيم. كنت أتمنى لو كان ذلك أفضل إذا تم ، بدلاً من ذلك ، استخلاص القيم الأولية من الكائنات المرصودة في مكون عالي الترتيب لتعيين الحالة الأولية. ربما يستطيع أحد قراء هذه المادة مشاركة النصائح في التعليقات حول كيفية القيام بذلك.
يمكن العثور
هنا على رمز مشروع البرنامج الذي قمنا به
هنا .
الملخص
الهدف الرئيسي من هذه المقالة هو إظهار نهج بديل لتطوير تطبيقات التفاعل باستخدام RxJS. نأمل أنه أعطاك طعامًا للتفكير. في بعض الأحيان لا يكون Redux و MobX ضروريين ، ولكن ربما في مثل هذه المواقف ، سيكون RxJS هو ما هو مناسب لمشروع محدد.
أعزائي القراء! هل تستخدم RxJS عند تطوير تطبيقات التفاعل؟
