مقدمة إلى Redux Saga

Redux Saga هي مكتبة تستخدم للتعامل مع الآثار الجانبية في Redux. عندما تطلق إجراءً ما ، يتغير شيء ما في حالة التطبيق وقد تحتاج إلى القيام بشيء ناجم عن هذا التغيير في الحالة

متى تستخدم Redux Saga

في تطبيق يستخدمإعادة، عندما تطلق إجراءً يتغير شيء ما في حالة التطبيق.

عندما يحدث هذا ، قد تحتاج إلى القيام بشيء مشتق من هذا التغيير في الحالة.

على سبيل المثال قد ترغب في:

  • قم بإجراء مكالمة HTTP إلى الخادم
  • إرسال حدث WebSocket
  • إحضار بعض البيانات من ملفGraphQLالخادم
  • حفظ شيء ما في ذاكرة التخزين المؤقت أو التخزين المحلي للمتصفح

... لقد خطرت لك الفكرة.

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

أدخل Redux Saga ، وهو برنامج وسيط من Redux يساعدك في مواجهة الآثار الجانبية.

مثال أساسي على استخدام Redux Saga

لتجنب الغوص في الكثير من النظريات قبل عرض بعض التعليمات البرمجية الفعلية ، أقدم بإيجاز كيف حللت مشكلة واجهتها عند إنشاء تطبيق نموذجي.

في غرفة الدردشة ، عندما يكتب مستخدم رسالة ، أعرض الرسالة فورًا على الشاشة ، لتقديم ملاحظات سريعة. يتم ذلك من خلال أإعادة العمل:

const addMessage = (message, author) => ({
  type: 'ADD_MESSAGE',
  message,
  author
})

وتتغير الحالة من خلال مخفض:

const messages = (state = [], action) => {
  switch (action.type) {
    case 'ADD_MESSAGE':
      return state.concat([{
        message: action.message,
        author: action.author
      }])
    default:
      return state
  }
}

تقوم بتهيئة Redux Saga عن طريق استيرادها أولاً ، ثم تطبيق ملفقصة طويلةكبرنامج وسيط لمتجر Redux:

//...
import createSagaMiddleware from 'redux-saga'
//...

ثم نقوم بإنشاء برمجية وسيطة ونطبقها على متجر Redux الذي تم إنشاؤه حديثًا:

const sagaMiddleware = createSagaMiddleware()

const store = createStore( reducers, applyMiddleware(sagaMiddleware) )

الخطوة الأخيرة هي تشغيل الملحمة. نستورده ونمرره إلى التابع run للوسيطة

import handleNewMessage from './sagas'
//...
sagaMiddleware.run(handleNewMessage)

نحتاج فقط إلى كتابة الملحمة في./sagas/index.js:

import { takeEvery } from 'redux-saga/effects'

const handleNewMessage = function* handleNewMessage(params) { const socket = new WebSocket(‘ws://localhost:8989’) yield takeEvery(‘ADD_MESSAGE’, (action) => { socket.send(JSON.stringify(action)) }) }

export default handleNewMessage

ما يعنيه هذا الرمز هو:كل مرةالADD_MESSAGEحرائق العمل ، نرسل رسالة إلىمآخذ الويبالخادم الذي يستجيب في هذه الحالة علىlocalhost:8989.

لاحظ استخدامfunction*، وهي ليست وظيفة عادية ، ولكن أمولد كهرباء.

كيف تعمل وراء الكواليس

كونهإعادةيمكن للبرمجيات الوسيطة ، Redux Saga اعتراض إجراءات Redux وإدخال وظائفها الخاصة.

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

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

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

أقصة طويلةهومولد كهرباءوظيفة. عندمايعديتم تشغيل وأسفرت، الوسيطةيعلقالقصة طويلةحتى اليعديكونتم الحل.

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

داخل رمز الملحمة ، ستقوم بإنشاء ملفتأثيراتباستخدام بعض الوظائف المساعدة الخاصة التي يوفرهاredux-sagaصفقة. للبدء ، يمكننا سرد:

  • takeEvery()
  • takeLatest()
  • take()
  • call()
  • put()

عندماتأثيريتم تنفيذقصة طويلةيكونمتوقف مؤقتاحتى التأثيريكوناستيفاء.

على سبيل المثال:

import { takeEvery } from 'redux-saga/effects'

const handleNewMessage = function* handleNewMessage(params) { const socket = new WebSocket(‘ws://localhost:8989’) yield takeEvery(‘ADD_MESSAGE’, (action) => { socket.send(JSON.stringify(action)) }) }

export default handleNewMessage

عندماالوسيطةينفذhandleNewMessageملحمة ، ذلكتوقففي الyield takeEveryتعليمات وينتظر(بشكل غير متزامن، بالطبع) حتىADD_MESSAGEالعملأرسل. ثم يقوم بتشغيل رد الاتصال الخاص به ، وقصة طويلةعلبةسيرة ذاتية.

المساعدين الأساسيين

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

دعنا نقدم المساعدة الأساسية التي يمكنك استخدامها لتشغيل التأثيرات الخاصة بك:

  • takeEvery()
  • takeLatest()
  • take()
  • put()
  • call()

takeEvery()

takeEvery()، المستخدم في بعض الأمثلة ، هو أحد هؤلاء المساعدين.

في الكود:

import { takeEvery } from 'redux-saga/effects'

function* watchMessages() { yield takeEvery(‘ADD_MESSAGE’, postMessageToServer) }

الwatchMessagesالمولد يتوقف مؤقتًا حتىADD_MESSAGEحرائق العمل ، وكل مرةحرائق ، سوف تستدعيpostMessageToServerتعمل بشكل لا نهائي ومتزامن (ليست هناك حاجة إلىpostMessageToServerلإنهاء تنفيذه قبل تشغيل جديد مرة واحدة)

takeLatest()

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

كما هو الحال معtakeEvery()لا يتوقف المولد أبدًا ويستمر في تشغيل التأثير عند حدوث الإجراء المحدد

take()

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

put()

يرسل إجراءً إلى متجر Redux. بدلاً من المرور في متجر Redux أو إجراء الإرسال إلى الملحمة ، يمكنك فقط استخدامput():

yield put({ type: 'INCREMENT' })
yield put({ type: "USER_FETCH_SUCCEEDED", data: data })

التي تُرجع كائنًا عاديًا يمكنك فحصه بسهولة في اختباراتك (المزيد عن الاختبار لاحقًا).

call()

عندما تريد استدعاء بعض الوظائف في إحدى الملحمات ، يمكنك القيام بذلك باستخدام استدعاء دالة عادي يُرد بوعد:

delay(1000)

لكن هذا لا يلعب بشكل جيد مع الاختبارات. بدلا من،call()يتيح لك التفاف استدعاء الوظيفة وإرجاع كائن يمكن فحصه بسهولة:

call(delay, 1000)

عائدات

{ CALL: {fn: delay, args: [1000]}}

تشغيل التأثيرات بالتوازي

يمكن تشغيل التأثيرات بالتوازي باستخدامall()وrace()، والتي تختلف كثيرًا في ما يفعلونه.

all()

إذا كنت تكتب

import { call } from 'redux-saga/effects'

const todos = yield call(fetch, ‘/api/todos’) const user = yield call(fetch, ‘/api/user’)

الثانيfetch()لن يتم تنفيذ المكالمة حتى تنجح المكالمة الأولى.

لتنفيذها بالتوازي ، لفهاall():

import { all, call } from 'redux-saga/effects'

const [todos, user] = yield all([ call(fetch, ‘/api/todos’), call(fetch, ‘/api/user’) ])

all()لن يتم حلها حتى كليهماcall()إرجاع.

race()

race()يختلف عنall()من خلال عدم انتظار عودة جميع مكالمات المساعدين. إنه فقط ينتظر عودة أحدهم ، وقد انتهى الأمر.

إنه سباق لمعرفة من سينتهي أولاً ، ثم ننسى المشاركين الآخرين.

يتم استخدامه عادةً لإلغاء مهمة في الخلفية تعمل إلى الأبد حتى يحدث شيء ما:

import { race, call, take } from 'redux-saga/effects'

function* someBackgroundTask() { while(1) { //… } }

yield race([ bgTask: call(someBackgroundTask), cancel: take(‘CANCEL_TASK’) ])

عندماCANCEL_TASKيتم إصدار الإجراء ، نوقف المهمة الأخرى التي كانت ستعمل إلى الأبد.

تحميل مجانيكتيب رد الفعل


المزيد من البرامج التعليمية للتفاعل: