بشكل افتراضي ، تكون الإجراءات في Redux متزامنة ، وهي مشكلة بالنسبة للتطبيق الذي يحتاج إلى التفاعل مع API الخاص بالخادم ، أو تنفيذ إجراءات أخرى غير متزامنة. لحسن الحظ ، يوفر Redux لنا شيء مثل الوسيطة ، التي تقف بين إرسال العمل ومخفض. هناك نوعان من المكتبات الوسيطة الأكثر شعبية للأفعال غير المتزامنة في Redux ، وهما Redux Thunk و Redux Saga . في هذا المنصب سننظر في الأول.Redux Thunk هي مكتبة برمجية تسمح لك بالاتصال بمنشئ الإجراء ، وإرجاع دالة بدلاً من كائن. تأخذ الدالة أسلوب الإرسال كوسيطة ، بحيث بعد اكتمال العملية غير المتزامنة ، استخدمها لإرسال الإجراء المتزامن المنتظم داخل جسم الوظيفة.
إذا كنت مهتمًا ، فإن Thunk هو مفهوم في عالم البرمجة عند استخدام دالة لتأخير العملية.التثبيت والإعداد
أولاً ، أضف حزمة
redux-thunk إلى مشروعك:
$ yarn add redux-thunk
بعد ذلك ، قم بإضافة برنامج وسيط عندما تقوم بإنشاء
متجر للتطبيق الخاص بك باستخدام تطبيق
البرامج الوسيطة التي يوفرها Redux:
index.js import React from 'react'; import ReactDOM from 'react-dom'; import { createStore, applyMiddleware } from 'redux'; import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; import rootReducer from './reducers'; import App from './App';
الاستخدام الرئيسي
عادة ، يتم استخدام Redux-Thunk للطلبات غير المتزامنة إلى واجهة برمجة تطبيقات خارجية ، لتلقي البيانات أو حفظها. Redux-Thunk يجعل من السهل إرسال الإجراءات التي تتبع "دورة الحياة" لطلب API الخارجي.
على سبيل المثال ، لدينا تطبيق ما يجب عمله بانتظام. عندما نقر على "add todo" ، عادة ، سيتم إرسال الإجراء الأول ، والذي يشير إلى بداية إضافة todo جديد. ثم ، إذا تم إنشاء عنصر ما يجب عمله وإعادته بنجاح بواسطة الخادم ، فسيتم إرسال إجراء آخر باستخدام عنصر المهام الجديد الخاص بنا ، ونجحت العملية. إذا قام الخادم بإرجاع خطأ لسبب ما ، فبدلاً من إضافة مهمة جديدة ، يتم عرض إجراء خطأ أنه لم يتم إكمال العملية.
دعونا نرى كيف يمكن تنفيذ ذلك باستخدام Redux-Thunk. في المكون ، يتم إرسال الإجراء كالمعتاد:
AddTodo.js import { connect } from 'react-redux'; import { addTodo } from '../actions'; import NewTodo from '../components/NewTodo'; const mapDispatchToProps = dispatch => { return { onAddTodo: todo => { dispatch(addTodo(toto)); } }; }; export default connect( null, mapDispatchToProps )(NewTodo);
في العمل نفسه ، فإن الوضع أكثر إثارة للاهتمام. هنا سوف نستخدم مكتبة Axios لطلبات ajax. إذا لم يكن مثبتًا لديك ، فأضفه كما يلي:
سنقدم طلب POST إلى العنوان -
jsonplaceholder.typicode.com/todos :
الإجراءات / index.js import { ADD_TODO_SUCCESS, ADD_TODO_FAILURE, ADD_TODO_STARTED, DELETE_TODO } from './types'; import axios from 'axios'; export const addTodo = ({ title, userId }) => { return dispatch => { dispatch(addTodoStarted()); axios .post(`https://jsonplaceholder.typicode.com/todos`, { title, userId, completed: false }) .then(res => { dispatch(addTodoSuccess(res.data)); }) .catch(err => { dispatch(addTodoFailure(err.message)); }); }; }; const addTodoSuccess = todo => ({ type: ADD_TODO_SUCCESS, payload: { ...todo } }); const addTodoStarted = () => ({ type: ADD_TODO_STARTED }); const addTodoFailure = error => ({ type: ADD_TODO_FAILURE, payload: { error } });
لاحظ كيف
يقوم مُنشئ الإجراء
addTodo بإرجاع دالة ، بدلاً من الإجراء المعتاد للكائن. هذه الوظيفة تأخذ وسيطة الإرسال من المتجر.
داخل نص الوظيفة ، نرسل أولاً الإجراء المتزامن المعتاد ، والذي يشير إلى أننا بدأنا في إضافة مهمة جديدة باستخدام واجهة برمجة تطبيقات خارجية. بكلمات بسيطة - تم إرسال الطلب إلى الخادم. ثم ، نحن في الواقع تقديم طلب POST إلى الخادم باستخدام Axios. في حالة وجود إجابة إيجابية من الخادم ، نرسل الإجراء المتزامن باستخدام البيانات الواردة من الخادم. ولكن في حالة حدوث خطأ من الخادم ، نقوم بإرسال إجراء متزامن آخر مع رسالة خطأ.
عندما نستخدم واجهة برمجة تطبيقات تكون خارجية (عن بُعد) حقًا ، مثل
JSONPlaceholder في حالتنا ، فمن السهل أن تلاحظ وجود تأخير حتى وصول استجابة الخادم. ولكن إذا كنت تعمل مع خادم محلي ، فقد تأتي الإجابة بسرعة كبيرة ، لذلك لن تلاحظ أي تأخير. لراحتك ، يمكنك إضافة تأخير مصطنع عند تطوير:
إجراءات / index.js (جزء من الكود) export const addTodo = ({ title, userId }) => { return dispatch => { dispatch(addTodoStarted()); axios .post(ENDPOINT, { title, userId, completed: false }) .then(res => { setTimeout(() => { dispatch(addTodoSuccess(res.data)); }, 2500); }) .catch(err => { dispatch(addTodoFailure(err.message)); }); }; };
ولاختبار برنامج نصي مع وجود خطأ ، يمكنك إلقاء خطأ مباشرةً:
إجراءات / index.js (جزء من الكود) export const addTodo = ({ title, userId }) => { return dispatch => { dispatch(addTodoStarted()); axios .post(ENDPOINT, { title, userId, completed: false }) .then(res => { throw new Error('NOT!');
من أجل الاكتمال ، فيما يلي مثال على كيفية ظهور مُخَفِّف ما يجب عمله من أجل معالجة "دورة الحياة" الكاملة للطلب:
مخفضات / todoReducer.js import { ADD_TODO_SUCCESS, ADD_TODO_FAILURE, ADD_TODO_STARTED, DELETE_TODO } from '../actions/types'; const initialState = { loading: false, todos: [], error: null }; export default function todosReducer(state = initialState, action) { switch (action.type) { case ADD_TODO_STARTED: return { ...state, loading: true }; case ADD_TODO_SUCCESS: return { ...state, loading: false, error: null, todos: [...state.todos, action.payload] }; case ADD_TODO_FAILURE: return { ...state, loading: false, error: action.payload.error }; default: return state; } }
getState
الوظيفة التي يتم إرجاعها بواسطة منشئ الإجراء غير المتزامن باستخدام Redux-Thunk تقبل أيضًا طريقة
getState كوسيطة ثانية ، والتي تسمح لك بالحصول على الحالة مباشرةً داخل منشئ الإجراء:
إجراءات / index.js (جزء من الكود) export const addTodo = ({ title, userId }) => { return (dispatch, getState) => { dispatch(addTodoStarted()); console.log('current state:', getState());
عند تنفيذ هذا الرمز ، سيتم ببساطة إخراج الحالة الحالية إلى وحدة التحكم. على سبيل المثال:
{loading: true, todos: Array(1), error: null}
يمكن أن يكون استخدام getState مفيدًا عندما تحتاج إلى رد فعل مختلف ، اعتمادًا على الحالة الحالية. على سبيل المثال ، إذا حصرنا الحد الأقصى لعدد العناصر التي يجب فرضها على 4 ، فيمكننا ببساطة الخروج من الوظيفة إذا تم تجاوز هذا الحد:
إجراءات / index.js (جزء من الكود) export const addTodo = ({ title, userId }) => { return (dispatch, getState) => { const { todos } = getState(); if (todos.length >= 4) return; dispatch(addTodoStarted());
حقيقة ممتعة - هل تعلم أن كود Redux-Thunk يتكون من 14 سطرًا فقط؟ يمكنك التحقق من كيفية عمل الوسيطة Redux-Thunk أسفل الغطاء
رابط إلى المقال الأصلي -
إجراءات Redux غير المتزامنة باستخدام Redux Thunk .