كيفية القيام بأعمال Redux غير المتزامنة باستخدام Redux-Thunk

تحيات حبر! أقدم إليكم ترجمة المقال - إجراءات Redux غير المتزامنة باستخدام Redux Thunk ، مؤلف - Alligator.io


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

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

إذا كنت مهتمًا ، فإن Thunk هو مفهوم في عالم البرمجة عند استخدام دالة لتأخير العملية.

التثبيت والإعداد


أولاً ، أضف حزمة redux-thunk إلى مشروعك:

$ yarn add redux-thunk # ,   npm: $ npm install 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'; //  applyMiddleware,   thunk middleware   const store = createStore(rootReducer, applyMiddleware(thunk)); ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ); 

الاستخدام الرئيسي


عادة ، يتم استخدام 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. إذا لم يكن مثبتًا لديك ، فأضفه كما يلي:

 # Yarn $ yarn add axios # npm $ npm install axios --save 

سنقدم طلب 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!'); // dispatch(addTodoSuccess(res.data)); }) .catch(err => { dispatch(addTodoFailure(err.message)); }); }; }; 

من أجل الاكتمال ، فيما يلي مثال على كيفية ظهور مُخَفِّف ما يجب عمله من أجل معالجة "دورة الحياة" الكاملة للطلب:

مخفضات / 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 .

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


All Articles