একটি সময়সীমা সহ একটি রেডাক্স অ্যাকশন কীভাবে প্রেরণ করবেন?


889

আমার একটি ক্রিয়া রয়েছে যা আমার আবেদনের বিজ্ঞপ্তি স্থিতিকে আপডেট করে। সাধারণত, এই বিজ্ঞপ্তিটি কোনও ধরণের ত্রুটি বা তথ্য হবে। তারপরে আমার 5 সেকেন্ডের পরে আরও একটি ক্রিয়া প্রেরণ করা দরকার যা প্রারম্ভিকটিতে বিজ্ঞপ্তিটি ফিরিয়ে দেবে, সুতরাং কোনও বিজ্ঞপ্তি নেই। এর পিছনে মূল কারণটি কার্যকারিতা সরবরাহ করা যেখানে বিজ্ঞপ্তিগুলি 5 সেকেন্ড পরে স্বয়ংক্রিয়ভাবে অদৃশ্য হয়ে যায়।

setTimeoutঅন্য ক্রিয়াটি ব্যবহার এবং ফিরে আসার ক্ষেত্রে আমার ভাগ্য নেই এবং এটি অনলাইনে কীভাবে করা হয় তা খুঁজে পাচ্ছি না। সুতরাং কোন পরামর্শ স্বাগত।


30
redux-sagaআপনি থঙ্কস থেকে আরও ভাল কিছু চাইলে আমার ভিত্তিক উত্তরটি পরীক্ষা করতে ভুলবেন না । দেরিতে উত্তর যাতে এটি প্রদর্শিত হওয়ার আগে আপনাকে দীর্ঘ সময় স্ক্রোল করতে হবে :) এর অর্থ এটি পড়ার মতো নয়। এখানে একটি শর্টকাট: stackoverflow.com/a/38574266/82609
সেবাস্তিয়ান লরবার

5
আপনি যখনই সেটটাইমআউট করেন তখন কম্পিটারউইলআউনমাউন্ট লাইফ চক্র পদ্ধতিতে ক্লিয়ারটাইমআউট ব্যবহার করে টাইমার সাফ করতে ভুলবেন না
হেমাদ্রি দাসারী

2
রিডেক্স-সাগা দুর্দান্ত তবে তারা জেনারেটর ফাংশন থেকে টাইপ করা প্রতিক্রিয়ার জন্য সমর্থন বলে মনে হচ্ছে না। আপনি যদি প্রতিক্রিয়ার সাথে টাইপস্ক্রিপ্ট ব্যবহার করছেন তবে তা গুরুত্বপূর্ণ।
ক্রিশ্চিয়ান রামিরেজ

উত্তর:


2614

মধ্যে পড়ে না একটি লাইব্রেরি চিন্তা সবকিছু কেমন করতে বিহিত করা উচিত ফাঁদ । আপনি যদি জাভাস্ক্রিপ্টের সময়সীমা নিয়ে কিছু করতে চান তবে আপনার ব্যবহার করা দরকার setTimeout। রেডাক্স ক্রিয়াগুলি আলাদা হওয়া উচিত বলে কোনও কারণ নেই।

রেডাক্স করে অ্যাসিঙ্ক্রোনাস কাপড় সাথে ডিল করার কিছু বিকল্প উপায় প্রস্তাব, কিন্তু যখন আপনি বোঝেন যে আপনি অত্যধিক কোড পুনরায় আছেন কেবলমাত্র সেই ব্যবহার করা উচিত। আপনার যদি এই সমস্যা না হয় তবে ভাষাটি যা দেয় তা ব্যবহার করুন এবং সহজ সমাধানের জন্য যান।

অ্যাসিঙ্ক কোড ইনলাইন লেখা

এটি এখন পর্যন্ত সবচেয়ে সহজ উপায়। এবং এখানে রেডাক্সের সাথে নির্দিষ্ট কিছু নেই।

store.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
  store.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)

একইভাবে, একটি সংযুক্ত উপাদানটির ভিতরে থেকে:

this.props.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
  this.props.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)

পার্থক্যটি হ'ল কোনও সংযুক্ত উপাদানটিতে সাধারণত আপনি নিজেই স্টোরটি অ্যাক্সেস করতে পারেন না, তবে হয় dispatch()বা নির্দিষ্ট ক্রিয়াকর্মীদের প্রপস হিসাবে ইনজেকশন পান। তবে এটি আমাদের জন্য কোনও পার্থক্য করে না।

আপনি যদি বিভিন্ন উপাদান থেকে একই ক্রিয়াকলাপটি প্রেরণ করার সময় টাইপগুলি তৈরি করতে পছন্দ না করেন তবে অ্যাকশন অবজেক্টগুলিকে ইনলাইন প্রেরণের পরিবর্তে আপনি অ্যাকশন স্রষ্টাকে আহরণ করতে চাইতে পারেন:

// actions.js
export function showNotification(text) {
  return { type: 'SHOW_NOTIFICATION', text }
}
export function hideNotification() {
  return { type: 'HIDE_NOTIFICATION' }
}

// component.js
import { showNotification, hideNotification } from '../actions'

this.props.dispatch(showNotification('You just logged in.'))
setTimeout(() => {
  this.props.dispatch(hideNotification())
}, 5000)

বা, আপনি যদি আগে তাদের সাথে আবদ্ধ হন connect():

this.props.showNotification('You just logged in.')
setTimeout(() => {
  this.props.hideNotification()
}, 5000)

এখন পর্যন্ত আমরা কোনও মিডলওয়্যার বা অন্যান্য উন্নত ধারণা ব্যবহার করি নি।

অ্যাসিঙ্ক অ্যাকশন স্রষ্টা সরিয়ে নেওয়া হচ্ছে

উপরের পদ্ধতিটি সাধারণ ক্ষেত্রে ঠিকঠাক কাজ করে তবে আপনি দেখতে পাবেন যে এতে কয়েকটি সমস্যা রয়েছে:

  • এটি আপনাকে কোনও নোটিফিকেশন দেখাতে চাইলে এই যুক্তিকে সদৃশ করতে বাধ্য করে forces
  • বিজ্ঞপ্তিগুলির কোনও আইডি নেই তাই যদি আপনি দুটি বিজ্ঞপ্তি দ্রুত পর্যায়ে দেখান তবে আপনার কাছে একটি জাতি শর্ত থাকবে। প্রথম টাইমআউট শেষ হয়ে গেলে, এটি প্রেরণ করবে HIDE_NOTIFICATION, ভুলক্রমে দ্বিতীয় বিজ্ঞপ্তিটি সময়সীমার পরে খুব শীঘ্রই লুকিয়ে রাখবে।

এই সমস্যাগুলি সমাধান করার জন্য, আপনাকে একটি ফাংশন নিষ্কাশন করতে হবে যা সময়সীমা যুক্তিকে কেন্দ্রীভূত করে এবং এই দুটি ক্রিয়া প্রেরণ করে। এটি দেখতে এটির মতো দেখাবে:

// actions.js
function showNotification(id, text) {
  return { type: 'SHOW_NOTIFICATION', id, text }
}
function hideNotification(id) {
  return { type: 'HIDE_NOTIFICATION', id }
}

let nextNotificationId = 0
export function showNotificationWithTimeout(dispatch, text) {
  // Assigning IDs to notifications lets reducer ignore HIDE_NOTIFICATION
  // for the notification that is not currently visible.
  // Alternatively, we could store the timeout ID and call
  // clearTimeout(), but we’d still want to do it in a single place.
  const id = nextNotificationId++
  dispatch(showNotification(id, text))

  setTimeout(() => {
    dispatch(hideNotification(id))
  }, 5000)
}

এখন উপাদানগুলি showNotificationWithTimeoutএই যুক্তিকে অনুলিপি করা বা বিভিন্ন বিজ্ঞপ্তি সহ জাতিদের শর্ত না করে ব্যবহার করতে পারে :

// component.js
showNotificationWithTimeout(this.props.dispatch, 'You just logged in.')

// otherComponent.js
showNotificationWithTimeout(this.props.dispatch, 'You just logged out.')    

কেন প্রথম যুক্তি হিসাবে showNotificationWithTimeout()গ্রহণ dispatch? কারণ এটি ক্রিয়াকলাপ দোকানে প্রেরণ করা প্রয়োজন। সাধারণত কোনও উপাদানটির অ্যাক্সেস থাকে dispatchতবে আমরা যেহেতু বাহ্যিক ফাংশন প্রেরণের উপর নিয়ন্ত্রণ নিতে চাই তাই আমাদের এটি প্রেরণের উপর নিয়ন্ত্রণ দেওয়া দরকার।

যদি আপনি কোনও মডিউল থেকে একটি সিঙ্গলটন স্টোর রফতানি করে থাকেন তবে আপনি কেবল এটির এবং dispatchসরাসরি তার পরিবর্তে আমদানি করতে পারেন :

// store.js
export default createStore(reducer)

// actions.js
import store from './store'

// ...

let nextNotificationId = 0
export function showNotificationWithTimeout(text) {
  const id = nextNotificationId++
  store.dispatch(showNotification(id, text))

  setTimeout(() => {
    store.dispatch(hideNotification(id))
  }, 5000)
}

// component.js
showNotificationWithTimeout('You just logged in.')

// otherComponent.js
showNotificationWithTimeout('You just logged out.')    

এটি সহজ দেখাচ্ছে তবে আমরা এই পদ্ধতির প্রস্তাব দিই না । আমরা এটিকে অপছন্দ করার মূল কারণ হ'ল এটি স্টোরকে একটি সিঙ্গলটন হতে বাধ্য করে । এটি সার্ভার রেন্ডারিং বাস্তবায়ন করা খুব শক্ত করে তোলে । সার্ভারে, আপনি প্রতিটি অনুরোধটির নিজস্ব স্টোর রাখতে চাইবেন, যাতে বিভিন্ন ব্যবহারকারী বিভিন্ন প্রিলোডড ডেটা পান।

একটি সিঙ্গলটন স্টোরও পরীক্ষা আরও শক্ত করে তোলে। অ্যাকশন স্রষ্টাদের পরীক্ষা করার সময় আপনি আর কোনও স্টোরকে উপহাস করতে পারবেন না কারণ তারা নির্দিষ্ট মডিউল থেকে রফতানি করা একটি নির্দিষ্ট রিয়েল স্টোরের উল্লেখ করে। আপনি এর রাজ্যটি বাইরে থেকে পুনরায় সেট করতে পারবেন না।

সুতরাং আপনি যখন প্রযুক্তিগতভাবে কোনও মডিউল থেকে একটি সিঙ্গলটন স্টোর রফতানি করতে পারেন, আমরা এটি নিরুৎসাহিত করি। আপনার অ্যাপটি কখনই সার্ভার রেন্ডারিং যুক্ত করবে না এমনটি নিশ্চিত না হলে এটি করবেন না।

পূর্ববর্তী সংস্করণে ফিরে আসা:

// actions.js

// ...

let nextNotificationId = 0
export function showNotificationWithTimeout(dispatch, text) {
  const id = nextNotificationId++
  dispatch(showNotification(id, text))

  setTimeout(() => {
    dispatch(hideNotification(id))
  }, 5000)
}

// component.js
showNotificationWithTimeout(this.props.dispatch, 'You just logged in.')

// otherComponent.js
showNotificationWithTimeout(this.props.dispatch, 'You just logged out.')    

এটি যুক্তির অনুলিপিকরণ সহ সমস্যাগুলি সমাধান করে এবং বর্ণের পরিস্থিতি থেকে আমাদের বাঁচায়।

থংক মিডলওয়্যার

সহজ অ্যাপ্লিকেশনগুলির জন্য, পদ্ধতির যথেষ্ট হওয়া উচিত। আপনি যদি এতে সন্তুষ্ট হন তবে মিডলওয়্যার সম্পর্কে চিন্তা করবেন না।

বৃহত্তর অ্যাপ্লিকেশনগুলিতে, তবে আপনার আশেপাশে কিছু অসুবিধা খুঁজে পেতে পারে।

উদাহরণস্বরূপ, এটি দুর্ভাগ্যজনক বলে মনে হচ্ছে যে আমাদের dispatchচারপাশে যেতে হবে। এটি কনটেইনার এবং উপস্থাপক উপাদানগুলি পৃথক করা শক্ত করে তোলে কারণ যে কোনও উপাদান যা উপরের পদ্ধতিতে সংযোজিতভাবে Redux ক্রিয়া প্রেরণ করে সেটিকে dispatchপ্রপ হিসাবে গ্রহণ করতে হবে যাতে এটি আরও পাস করতে পারে। আপনি কেবল অ্যাকশন নির্মাতাদের সাথে connect()আর আবদ্ধ করতে পারবেন না কারণ showNotificationWithTimeout()সত্যই কোনও অ্যাকশন স্রষ্টা নয়। এটি কোনও রেডাক্স ক্রিয়া ফিরিয়ে দেয় না।

তদ্ব্যতীত, কোন ফাংশনগুলি সিঙ্ক্রোনাস অ্যাকশন নির্মাতাদের মতো showNotification()এবং কোনটি অ্যাসিনক্রোনাস সহায়ক পছন্দ করে তা মনে রাখা অবাস্তব হতে পারে showNotificationWithTimeout()। আপনাকে এগুলি আলাদাভাবে ব্যবহার করতে হবে এবং একে অপরের সাথে ভুল না করার বিষয়ে সতর্ক থাকতে হবে।

সহায়তাকারী ফাংশন সরবরাহ dispatchকরার এই প্যাটার্নটিকে "বৈধতা দেওয়ার" উপায় খুঁজে বের করার প্রেরণা ছিল এবং রেডাক্স যেমন অ্যাসিনক্রোনাস অ্যাকশন নির্মাতাদের সম্পূর্ণ ভিন্ন ফাংশন না করে সাধারণ ক্রিয়া নির্মাতাদের একটি বিশেষ ক্ষেত্রে হিসাবে "দেখতে" সহায়তা করে।

আপনি যদি এখনও আমাদের সাথে থাকেন এবং আপনি যদি আপনার অ্যাপ্লিকেশনটিতে একটি সমস্যা হিসাবে স্বীকৃতি পান তবে আপনাকে রেডাক্স থাঙ্ক মিডলওয়্যারটি ব্যবহার করতে স্বাগত জানানো হবে ।

সংক্ষেপে, রেডাক্স থাঙ্ক রেডাক্সকে বিশেষ ধরণের ক্রিয়াকলাপগুলি সনাক্ত করতে শেখায় যা সত্যিকারের কার্যাদি:

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'

const store = createStore(
  reducer,
  applyMiddleware(thunk)
)

// It still recognizes plain object actions
store.dispatch({ type: 'INCREMENT' })

// But with thunk middleware, it also recognizes functions
store.dispatch(function (dispatch) {
  // ... which themselves may dispatch many times
  dispatch({ type: 'INCREMENT' })
  dispatch({ type: 'INCREMENT' })
  dispatch({ type: 'INCREMENT' })

  setTimeout(() => {
    // ... even asynchronously!
    dispatch({ type: 'DECREMENT' })
  }, 1000)
})

এই মিডওয়্যারটি সক্ষম থাকলে, আপনি যদি কোনও ফাংশন প্রেরণ করেন তবে রেডাক্স থাঙ্ক মিডলওয়্যার এটি dispatchআর্গুমেন্ট হিসাবে দেবে । এটি এই জাতীয় ক্রিয়াকলাপগুলিকে "গিলতেও" দেবে তাই আপনার হ্রাসকারীদের উদ্ভট ফাংশন যুক্তি পাওয়ার বিষয়ে চিন্তা করবেন না। আপনার হ্রাসকারীরা কেবল প্লেইন অবজেক্ট ক্রিয়াগুলি গ্রহণ করবে - হয় প্রত্যক্ষভাবে নির্গত হয়, বা আমরা সুনির্দিষ্টভাবে বর্ণনা হিসাবে ফাংশনগুলি দ্বারা নির্গত হয়।

এটি খুব দরকারী বলে মনে হচ্ছে না, তাই না? এই বিশেষ পরিস্থিতিতে নয়। তবে এটি আমাদের showNotificationWithTimeout()নিয়মিত রেডাক্স অ্যাকশন নির্মাতা হিসাবে ঘোষণা করতে দেয় :

// actions.js
function showNotification(id, text) {
  return { type: 'SHOW_NOTIFICATION', id, text }
}
function hideNotification(id) {
  return { type: 'HIDE_NOTIFICATION', id }
}

let nextNotificationId = 0
export function showNotificationWithTimeout(text) {
  return function (dispatch) {
    const id = nextNotificationId++
    dispatch(showNotification(id, text))

    setTimeout(() => {
      dispatch(hideNotification(id))
    }, 5000)
  }
}

পূর্ববর্তী বিভাগে আমরা যেভাবে লিখেছি তার সাথে ফাংশনটি প্রায় একই রকম দেখুন। তবে এটি dispatchপ্রথম যুক্তি হিসাবে গ্রহণ করে না । এর পরিবর্তে এটি ফেরৎ একটি ফাংশন যে গ্রহণ করে dispatchপ্রথম আর্গুমেন্ট হিসাবে।

কীভাবে আমরা আমাদের উপাদানগুলিতে এটি ব্যবহার করব? অবশ্যই, আমরা এটি লিখতে পারে:

// component.js
showNotificationWithTimeout('You just logged in.')(this.props.dispatch)

কেবলমাত্র চায় এমন অভ্যন্তরীণ ফাংশনটি পেতে আমরা অ্যাসিঙ্ক অ্যাকশন স্রষ্টাকে কল করছি dispatchএবং তারপরে আমরা পাস করি dispatch

তবে এটি মূল সংস্করণের চেয়ে আরও বিশ্রী! কেন আমরা এমনকি সে পথে গেলাম?

আমি আপনাকে আগে যা বলেছিলাম তার কারণেই। যদি রেডাক্স থাঙ্ক মিডলওয়্যার সক্ষম থাকে, আপনি যে কোনও সময় অ্যাকশন অবজেক্টের পরিবর্তে কোনও ফাংশন প্রেরণের চেষ্টা করবেন, মিডলওয়্যার সেই ফাংশনটিকে dispatchনিজেই প্রথম আর্গুমেন্ট হিসাবে কল করবে

সুতরাং আমরা পরিবর্তে এটি করতে পারেন:

// component.js
this.props.dispatch(showNotificationWithTimeout('You just logged in.'))

অবশেষে, একটি অ্যাসিনক্রোনাস অ্যাকশন প্রেরণ করা (সত্যিকার অর্থে, ক্রিয়াগুলির একটি সিরিজ) উপাদানটিতে সিঙ্ক্রোনালি কোনও একক ক্রিয়া প্রেরণ করার চেয়ে আলাদা নয় looks কোনটি ভাল কারণ উপাদানগুলি সিঙ্ক্রোনালি বা অ্যাসিক্রোনোরিয়ালি কিছু ঘটে কিনা তা বিবেচনা করা উচিত নয়। আমরা কেবল এটি দূরে বিমূর্ত।

লক্ষ্য করুন যেহেতু আমরা রেডাক্সকে এই জাতীয় "বিশেষ" অ্যাকশন নির্মাতাদের চিনতে "শিখিয়েছি" (আমরা তাদেরকে থাঙ্ক অ্যাকশন স্রষ্টা বলি ), এখন আমরা এগুলিকে যে কোনও জায়গায় নিয়মিত কর্ম নির্মাতাদের ব্যবহার করতে পারি। উদাহরণস্বরূপ, আমরা এগুলি এগুলি ব্যবহার করতে পারি connect():

// actions.js

function showNotification(id, text) {
  return { type: 'SHOW_NOTIFICATION', id, text }
}
function hideNotification(id) {
  return { type: 'HIDE_NOTIFICATION', id }
}

let nextNotificationId = 0
export function showNotificationWithTimeout(text) {
  return function (dispatch) {
    const id = nextNotificationId++
    dispatch(showNotification(id, text))

    setTimeout(() => {
      dispatch(hideNotification(id))
    }, 5000)
  }
}

// component.js

import { connect } from 'react-redux'

// ...

this.props.showNotificationWithTimeout('You just logged in.')

// ...

export default connect(
  mapStateToProps,
  { showNotificationWithTimeout }
)(MyComponent)

থিংস স্টেট রিডিং

সাধারণত আপনার হ্রাসকারীদের পরবর্তী অবস্থা নির্ধারণের জন্য ব্যবসায় যুক্তিযুক্ত থাকে। তবে, ক্রিয়াগুলি প্রেরণের পরে হ্রাসকারীরা কেবল লাথি মারবে। আপনার যদি কোনও থঙ্ক অ্যাকশন নির্মাতার কোনও পার্শ্ব প্রতিক্রিয়া (যেমন কোনও এপিআই কল করা) হয় এবং আপনি কোনও শর্তে এটি আটকাতে চান তবে কী হবে?

থাঙ্ক মিডলওয়্যারটি ব্যবহার না করে আপনি কেবল উপাদানটির ভিতরে এই চেকটি করতে চাইবেন:

// component.js
if (this.props.areNotificationsEnabled) {
  showNotificationWithTimeout(this.props.dispatch, 'You just logged in.')
}

তবে, অ্যাকশন স্রষ্টাকে বের করার বিষয়টি হ'ল বহু উপাদানগুলিতে এই পুনরাবৃত্তি যুক্তিটিকে কেন্দ্রিক করে তোলা। ভাগ্যক্রমে, রেডাক্স থাঙ্ক আপনাকে রেডাক্স স্টোরের বর্তমান অবস্থা পড়ার জন্য একটি উপায় সরবরাহ করে। ছাড়াও dispatch, এটি পাস getStateফাংশন আপনি আপনার thunk কর্ম স্রষ্টা থেকে ফিরে দ্বিতীয় আর্গুমেন্ট হিসাবে। এটি থঙ্ককে স্টোরের বর্তমান অবস্থা পড়তে দেয়।

let nextNotificationId = 0
export function showNotificationWithTimeout(text) {
  return function (dispatch, getState) {
    // Unlike in a regular action creator, we can exit early in a thunk
    // Redux doesn’t care about its return value (or lack of it)
    if (!getState().areNotificationsEnabled) {
      return
    }

    const id = nextNotificationId++
    dispatch(showNotification(id, text))

    setTimeout(() => {
      dispatch(hideNotification(id))
    }, 5000)
  }
}

এই প্যাটার্নটি অপব্যবহার করবেন না। ক্যাশেড ডেটা উপলভ্য হলে এপিআই কলগুলি জামিন দেওয়ার পক্ষে ভাল তবে এটি আপনার ব্যবসায়ের যুক্তি তৈরির পক্ষে খুব ভাল ভিত্তি নয়। আপনি যদি getState()শর্তসাপেক্ষে বিভিন্ন ক্রিয়া প্রেরণের জন্য ব্যবহার করেন তবে পরিবর্তে ব্যবসায়িক যুক্তিটিকে হ্রাসকারীদের মধ্যে রাখার বিষয়টি বিবেচনা করুন।

পরবর্তী পদক্ষেপ

থুনস কীভাবে কাজ করে সে সম্পর্কে এখন আপনার একটি প্রাথমিক স্বীকৃতি, Redux async উদাহরণ যা সেগুলি ব্যবহার করে তা পরীক্ষা করে দেখুন।

আপনি এমন অনেকগুলি উদাহরণ খুঁজে পেতে পারেন যাতে থাঙ্কস প্রতিশ্রুতি দেয়। এটি প্রয়োজন হয় না তবে খুব সুবিধাজনক হতে পারে। রেডাক্স আপনি কী কাটা থেকে ফিরে আসবেন তা যত্ন করে না, তবে এটি আপনাকে এর থেকে ফেরতের মান দেয় dispatch()। এ কারণেই আপনি কোনও শঙ্কার কাছ থেকে কোনও প্রতিশ্রুতি ফিরিয়ে আনতে পারেন এবং কল করে এটি সম্পন্ন হওয়ার জন্য অপেক্ষা করতে পারেন dispatch(someThunkReturningPromise()).then(...)

আপনি জটিল থংক অ্যাকশন নির্মাতাকে কয়েকটি ছোট ছোট থান অ্যাকশন নির্মাতাদের মধ্যেও বিভক্ত করতে পারেন। dispatchThunks দ্বারা উপলব্ধ পদ্ধতি নিজেই thunks গ্রহণ করতে পারে, তাই আপনি প্যাটার্ন যাও recursively আবেদন করতে পারেন। আবার, এটি প্রতিশ্রুতিগুলির সাথে সর্বোত্তম কাজ করে কারণ আপনি তার উপরে অ্যাসিনক্রোনাস নিয়ন্ত্রণ প্রবাহকে প্রয়োগ করতে পারেন।

কিছু অ্যাপ্লিকেশানের জন্য, আপনি নিজেকে এমন পরিস্থিতিতে খুঁজে পেতে পারেন যেখানে আপনার অ্যাসিনক্রোনাস নিয়ন্ত্রণ প্রবাহের প্রয়োজনীয়তা থাঙ্কস দিয়ে প্রকাশ করা খুব জটিল। উদাহরণস্বরূপ, ব্যর্থ অনুরোধগুলির পুনরায় চেষ্টা করা, টোকেনগুলি দিয়ে পুনরায় অনুমোদনের প্রবাহ বা এই ধরণের লেখার সময় একটি ধাপে ধাপে অনবোর্ডিং খুব ভার্জোজ এবং ত্রুটি-প্রবণ হতে পারে। এই ক্ষেত্রে, আপনি আরও উন্নত অ্যাসিনক্রোনাস নিয়ন্ত্রণ প্রবাহ সমাধানগুলি যেমন Redux সাগা বা রেডাক্স লুপটি দেখতে চাইতে পারেন । এগুলি মূল্যায়ন করুন, আপনার প্রয়োজনগুলির সাথে প্রাসঙ্গিক উদাহরণগুলির তুলনা করুন এবং আপনার সবচেয়ে পছন্দ হওয়া পছন্দটি চয়ন করুন।

অবশেষে, আপনার যদি সত্যিকারের প্রয়োজন না থাকে তবে (থঙ্ক সহ) কিছু ব্যবহার করবেন না। মনে রাখবেন যে প্রয়োজনীয়তার উপর নির্ভর করে আপনার সমাধানটি তত সহজ দেখায়

store.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
  store.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)

আপনি কেন এমনটি করছেন তা না জানলে এটি ঘামবেন না।


27
অ্যাসিঙ্ক ক্রিয়াগুলি সাধারণ সমস্যার সাধারণ এবং মার্জিত সমাধানের মতো বলে মনে হয়। মিডওয়্যারের প্রয়োজন ছাড়াই কেন তাদের জন্য রেডুক্সে বেকড সমর্থন করা হচ্ছে না? এই উত্তরটি তখন আরও সংক্ষিপ্ত হতে পারে।
ফিল ম্যান্ডার

83
@ ফিলিমান্ডার কারণ github.com/raisemarketplace/redux-loop বা github.com/yelouafi/redux-saga এর মতো অনেক বিকল্প নিদর্শন রয়েছে যা মার্জিত (যেমন আরও বেশি নয়) are রেডাক্স একটি নিম্ন-স্তরের সরঞ্জাম। আপনি নিজের পছন্দ মতো সুপারসেট তৈরি করতে এবং এটি আলাদাভাবে বিতরণ করতে পারেন।
ড্যান আব্রামভ

16
আপনি কি এটি ব্যাখ্যা করতে পারেন: * ব্যবসায়ের যুক্তি হ্রাসকারীদের মধ্যে রাখার কথা বিবেচনা করুন * এর অর্থ কি আমার কোনও পদক্ষেপ প্রেরণ করা উচিত এবং তারপরে আমার রাষ্ট্রের উপর নির্ভর করে আরও কী কী পদক্ষেপ প্রেরণ করতে হবে তা রেডুসারে নির্ধারণ করা উচিত? আমার প্রশ্ন হ'ল আমি কি তখন অন্য ক্রিয়াগুলি সরাসরি আমার হ্রাসকারীর মধ্যে প্রেরণ করি এবং তা না হলে আমি সেগুলি কোথা থেকে প্রেরণ করব?
ফ্রোগিনভিয়েশন

25
এই বাক্যটি কেবল সিঙ্ক্রোনাস ক্ষেত্রে প্রযোজ্য। উদাহরণস্বরূপ, যদি আপনি লিখেন if (cond) dispatch({ type: 'A' }) else dispatch({ type: 'B' })সম্ভবত আপনার উচিত উচিত dispatch({ type: 'C', something: cond })এবং পরিবর্তে action.somethingএবং বর্তমান অবস্থার উপর নির্ভর করে হ্রাসকারীদের ক্রিয়াটি উপেক্ষা করা পছন্দ করুন ।
ড্যান আব্রামভ

29
@ ড্যানআব্রামভ আপনি কেবলমাত্র এইটির জন্য আমার উত্সাহ পেয়েছিলেন "যদি আপনার এই সমস্যা না হয় তবে ভাষার যেটি প্রস্তাব দেয় তা ব্যবহার করুন এবং সহজ সমাধানের দিকে যান না।" তবেই বুঝতে পারলাম কে লিখেছেন!
ম্যাট লেইস

188

রেডাক্স-কাহিনী ব্যবহার করা

ড্যান আব্রামভ যেমন বলেছিলেন, আপনি যদি আপনার অ্যাসিঙ্ক কোডের উপরে আরও উন্নত নিয়ন্ত্রণ চান তবে আপনি রিডুএক্স-সাগা একবার দেখে নিতে পারেন ।

এই উত্তরটি একটি সাধারণ উদাহরণ, যদি আপনি কেন আবেদনের জন্য রিডেক্স-সাগা কার্যকর হতে পারে সে সম্পর্কে আরও ভাল ব্যাখ্যা চান, তবে এই অন্য উত্তরটি দেখুন

সাধারণ ধারণাটি হ'ল রেডাক্স-সাগা একটি ES6 জেনারেটর দোভাষী দেয় যা আপনাকে সহজেই সিঙ্ক্রোনাস কোডের মতো দেখায় এমন অ্যাসিঙ্ক কোড লেখার অনুমতি দেয় (এই কারণেই আপনি প্রায়শই রেডাক্স-সাগায় লুপ করার সময় অসীম সন্ধান পাবেন)। কোনওভাবে, রেডাক্স-সাগা সরাসরি জাভাস্ক্রিপ্টের অভ্যন্তরে নিজস্ব ভাষা তৈরি করছে। রেডাক্স-সাগা প্রথমে কিছুটা শিখতে অসুবিধা বোধ করতে পারে, কারণ আপনার জেনারেটরগুলির বুনিয়াদি বোধ করা প্রয়োজন, তবে রেডাক্স-সাগা প্রস্তাবিত ভাষাও বুঝতে পারেন।

আমি এখানে রেডুএক্স-সাগা শীর্ষে তৈরি নটিফিকেশন সিস্টেমটি বর্ণনা করার জন্য এখানে চেষ্টা করব। এই উদাহরণটি বর্তমানে উত্পাদন হয়।

উন্নত বিজ্ঞপ্তি সিস্টেমের স্পেসিফিকেশন

  • আপনি প্রদর্শিত হতে একটি বিজ্ঞপ্তি অনুরোধ করতে পারেন
  • আপনি আড়াল করার জন্য একটি বিজ্ঞপ্তি অনুরোধ করতে পারেন
  • একটি বিজ্ঞপ্তি 4 সেকেন্ডের বেশি প্রদর্শিত হবে না
  • একাধিক বিজ্ঞপ্তি একই সাথে প্রদর্শিত হতে পারে
  • একই সাথে 3 টিরও বেশি বিজ্ঞপ্তি প্রদর্শিত হবে না
  • ইতিমধ্যে 3 প্রদর্শিত বিজ্ঞপ্তিগুলি থাকা অবস্থায় যদি কোনও বিজ্ঞপ্তি অনুরোধ করা হয়, তবে এটি সারি / স্থগিত করুন।

ফলাফল

আমার প্রযোজনা অ্যাপ্লিকেশন স্ট্যাম্পল.কমের স্ক্রিনশট

toasts

কোড

এখানে আমি বিজ্ঞপ্তির নাম দিয়েছি toastতবে এটি একটি নামকরণ বিশদ।

function* toastSaga() {

    // Some config constants
    const MaxToasts = 3;
    const ToastDisplayTime = 4000;


    // Local generator state: you can put this state in Redux store
    // if it's really important to you, in my case it's not really
    let pendingToasts = []; // A queue of toasts waiting to be displayed
    let activeToasts = []; // Toasts currently displayed


    // Trigger the display of a toast for 4 seconds
    function* displayToast(toast) {
        if ( activeToasts.length >= MaxToasts ) {
            throw new Error("can't display more than " + MaxToasts + " at the same time");
        }
        activeToasts = [...activeToasts,toast]; // Add to active toasts
        yield put(events.toastDisplayed(toast)); // Display the toast (put means dispatch)
        yield call(delay,ToastDisplayTime); // Wait 4 seconds
        yield put(events.toastHidden(toast)); // Hide the toast
        activeToasts = _.without(activeToasts,toast); // Remove from active toasts
    }

    // Everytime we receive a toast display request, we put that request in the queue
    function* toastRequestsWatcher() {
        while ( true ) {
            // Take means the saga will block until TOAST_DISPLAY_REQUESTED action is dispatched
            const event = yield take(Names.TOAST_DISPLAY_REQUESTED);
            const newToast = event.data.toastData;
            pendingToasts = [...pendingToasts,newToast];
        }
    }


    // We try to read the queued toasts periodically and display a toast if it's a good time to do so...
    function* toastScheduler() {
        while ( true ) {
            const canDisplayToast = activeToasts.length < MaxToasts && pendingToasts.length > 0;
            if ( canDisplayToast ) {
                // We display the first pending toast of the queue
                const [firstToast,...remainingToasts] = pendingToasts;
                pendingToasts = remainingToasts;
                // Fork means we are creating a subprocess that will handle the display of a single toast
                yield fork(displayToast,firstToast);
                // Add little delay so that 2 concurrent toast requests aren't display at the same time
                yield call(delay,300);
            }
            else {
                yield call(delay,50);
            }
        }
    }

    // This toast saga is a composition of 2 smaller "sub-sagas" (we could also have used fork/spawn effects here, the difference is quite subtile: it depends if you want toastSaga to block)
    yield [
        call(toastRequestsWatcher),
        call(toastScheduler)
    ]
}

এবং হ্রাসকারক:

const reducer = (state = [],event) => {
    switch (event.name) {
        case Names.TOAST_DISPLAYED:
            return [...state,event.data.toastData];
        case Names.TOAST_HIDDEN:
            return _.without(state,event.data.toastData);
        default:
            return state;
    }
};

ব্যবহার

আপনি কেবল TOAST_DISPLAY_REQUESTEDইভেন্ট প্রেরণ করতে পারেন । আপনি যদি 4 টি অনুরোধ প্রেরণ করেন তবে কেবলমাত্র 3 টি বিজ্ঞপ্তি প্রদর্শিত হবে এবং 1 তম বিজ্ঞপ্তিটি অদৃশ্য হয়ে যাওয়ার পরে চতুর্থটি একটু পরে উপস্থিত হবে।

নোট করুন যে আমি TOAST_DISPLAY_REQUESTEDজেএসএক্স থেকে প্রেরণের বিশেষ পরামর্শ দিচ্ছি না । আপনি বরং আরও একটি কাহিনী যোগ করতে চান যা আপনার ইতিমধ্যে বিদ্যমান অ্যাপ্লিকেশন ইভেন্টগুলি শোনায় এবং তারপরে প্রেরণ করুন TOAST_DISPLAY_REQUESTED: আপনার উপাদানটি যা বিজ্ঞপ্তিটি ট্রিগার করে, বিজ্ঞপ্তি সিস্টেমে শক্তভাবে মিলিত হতে হবে না।

উপসংহার

আমার কোড নিখুঁত নয় তবে কয়েক মাস ধরে বাগের সাথে উত্পাদনে চলে। রেডাক্স-সাগা এবং জেনারেটর প্রাথমিকভাবে কিছুটা শক্ত তবে আপনি তাদের বুঝতে পারলে এই ধরণের সিস্টেম তৈরি করা বেশ সহজ।

আরও জটিল নিয়মগুলি প্রয়োগ করা এমনকি এটি বেশ সহজ, যেমন:

  • যখন অনেকগুলি বিজ্ঞপ্তিগুলি "সারিবদ্ধ" হয়, তখন প্রতিটি বিজ্ঞপ্তির জন্য ডিসপ্লে-সময় কম দিন যাতে কাতার আকারটি দ্রুত হ্রাস পায়।
  • উইন্ডোর আকারের পরিবর্তনগুলি সনাক্ত করুন এবং সেই অনুযায়ী প্রদর্শিত বিজ্ঞপ্তির সর্বাধিক সংখ্যা পরিবর্তন করুন (উদাহরণস্বরূপ, ডেস্কটপ = 3, ফোন পোর্ট্রেট = 2, ফোন ল্যান্ডস্কেপ = 1)

সত্যিই, শুভকামি থঙ্কস দিয়ে এই ধরণের জিনিস সঠিকভাবে প্রয়োগ করে।

দ্রষ্টব্য আপনি রিডেক্স-অবজারভেবলের সাথে ঠিক একই ধরণের জিনিসটি করতে পারেন যা রিডেক্স-সাগার সাথে খুব মিল very এটি প্রায় একই রকম এবং জেনারেটর এবং আরএক্সজেএসের মধ্যে স্বাদের বিষয়।


18
আমি আশা করি প্রশ্নটি জিজ্ঞাসা করার সময় আপনার উত্তরটি আগে এসেছিল, কারণ সাগা পার্শ্ব প্রতিক্রিয়া লাইব্রেরিটিকে ব্যবসায়ের যুক্তির জন্য ব্যবহার করার সাথে আমি আরও একমত হতে পারি না। হ্রাসকারী এবং অ্যাকশন নির্মাতারা রাষ্ট্রের পরিবর্তনের জন্য। ওয়ার্কফ্লোগুলি রাষ্ট্রের রূপান্তর কার্য হিসাবে এক নয় the কর্মপ্রবাহগুলি ট্রানজিশনের মধ্য দিয়ে যায় তবে তারা নিজেরাই রূপান্তর হয় না। রেডাক্স + প্রতিক্রিয়াগুলির নিজস্ব এটির অভাব রয়েছে - এ কারণেই রেডাক্স সাগা এত দরকারী useful
অ্যাটিকাস

4
ধন্যবাদ, আমি এই কারণে রিডুক্স-সাগা জনপ্রিয় করার জন্য যথাসাধ্য চেষ্টা করার চেষ্টা করি :) খুব কম লোকই মনে করেন বর্তমানে রিডেক্স-সাগা কেবল থাঙ্কগুলির প্রতিস্থাপন এবং এটি দেখে না যে কীভাবে রিডেক্স-সাগা জটিল এবং ডিকোপলড ওয়ার্কফ্লোগুলিকে সক্ষম করে
সেবাস্তিয়ান লোরবার

1
যথাযথভাবে। ক্রিয়া ও হ্রাসকারীরা সমস্তই রাষ্ট্রের মেশিনের অংশ। কখনও কখনও, জটিল কর্মপ্রবাহের জন্য, রাষ্ট্রীয় মেশিনকে অর্কেস্টেট করার জন্য আপনার অন্য কিছু দরকার হয় যা সরাসরি রাজ্য মেশিনেরই অংশ নয়!
অ্যাটিকাস

2
ক্রিয়াগুলি: প্যালোডগুলি / ইভেন্টগুলিতে রূপান্তর অবস্থায় state হ্রাসকারী: রাষ্ট্রের রূপান্তর কার্যসমূহ। উপাদান: ব্যবহারকারীর ইন্টারফেসগুলি রাষ্ট্রকে প্রতিফলিত করে। তবে একটি বড় টুকরা অনুপস্থিত রয়েছে - আপনি কীভাবে অনেকগুলি রূপান্তর প্রক্রিয়া পরিচালনা করবেন যে সকলের নিজস্ব যুক্তি রয়েছে যা নির্ধারণ করে যে কোনটি পরবর্তী রূপান্তরটি সম্পাদন করবে? রেডাক্স সাগা!
অ্যাটিকাস

2
@ এমআরবার্ডো যদি আপনি আমার উত্তরটি মনোযোগ সহকারে পড়ে থাকেন তবে খেয়াল করবেন নোটিফিকেশন টাইমআউটগুলি বাস্তবে পরিচালনা করা হয় yield call(delay,timeoutValue);: এটি একই এপিআই নয় তবে এর একই প্রভাব রয়েছে
সেবাস্তিয়ান লোরবার

25

নমুনা প্রকল্প সহ একটি সংগ্রহস্থল

বর্তমান চারটি নমুনা প্রকল্প রয়েছে:

  1. অ্যাসিঙ্ক কোড ইনলাইন লেখা
  2. অ্যাসিঙ্ক অ্যাকশন স্রষ্টা সরিয়ে নেওয়া হচ্ছে
  3. রেডাক্স থাঙ্ক ব্যবহার করুন
  4. রেডাক্স সাগা ব্যবহার করুন

গৃহীত উত্তরটি দুর্দান্ত।

তবে কিছু অনুপস্থিত রয়েছে:

  1. কোনও চলমান নমুনা প্রকল্প নেই, কেবল কয়েকটি কোড স্নিপেট।
  2. অন্যান্য বিকল্পগুলির জন্য কোনও নমুনা কোড নেই, যেমন:
    1. রেডাক্স সাগা

সুতরাং আমি অনুপস্থিত জিনিসগুলি যুক্ত করতে হ্যালো অ্যাসিঙ্ক সংগ্রহস্থল তৈরি করেছি:

  1. চলমান প্রকল্পগুলি। আপনি এগুলি ডাউনলোড ও পরিবর্তন না করে চালাতে পারেন।
  2. আরও বিকল্পের জন্য নমুনা কোড সরবরাহ করুন:

রেডাক্স সাগা

গৃহীত উত্তরটি ইতিমধ্যে এসিঙ্ক কোড ইনলাইন, অ্যাসিঙ্ক অ্যাকশন জেনারেটর এবং রেডাক্স থঙ্কের জন্য নমুনা কোড স্নিপেট সরবরাহ করে। সম্পূর্ণতার জন্য, আমি রেডাক্স সাগা জন্য কোড স্নিপেট সরবরাহ:

// actions.js

export const showNotification = (id, text) => {
  return { type: 'SHOW_NOTIFICATION', id, text }
}

export const hideNotification = (id) => {
  return { type: 'HIDE_NOTIFICATION', id }
}

export const showNotificationWithTimeout = (text) => {
  return { type: 'SHOW_NOTIFICATION_WITH_TIMEOUT', text }
}

ক্রিয়াগুলি সহজ এবং খাঁটি।

// component.js

import { connect } from 'react-redux'

// ...

this.props.showNotificationWithTimeout('You just logged in.')

// ...

export default connect(
  mapStateToProps,
  { showNotificationWithTimeout }
)(MyComponent)

উপাদান সহ কিছুই বিশেষ নয়।

// sagas.js

import { takeEvery, delay } from 'redux-saga'
import { put } from 'redux-saga/effects'
import { showNotification, hideNotification } from './actions'

// Worker saga
let nextNotificationId = 0
function* showNotificationWithTimeout (action) {
  const id = nextNotificationId++
  yield put(showNotification(id, action.text))
  yield delay(5000)
  yield put(hideNotification(id))
}

// Watcher saga, will invoke worker saga above upon action 'SHOW_NOTIFICATION_WITH_TIMEOUT'
function* notificationSaga () {
  yield takeEvery('SHOW_NOTIFICATION_WITH_TIMEOUT', showNotificationWithTimeout)
}

export default notificationSaga

সাগস ইএস 6 জেনারেটরের উপর ভিত্তি করে

// index.js

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

const sagaMiddleware = createSagaMiddleware()

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

sagaMiddleware.run(saga)

রেডাক্স থঙ্কের সাথে তুলনা করা

পেশাদাররা

  • আপনি কলব্যাক নরকে শেষ করবেন না।
  • আপনি সহজেই আপনার অ্যাসিনক্রোনাস প্রবাহ পরীক্ষা করতে পারেন।
  • আপনার ক্রিয়া শুদ্ধ থাকে।

কনস

  • এটি ES6 জেনারেটরের উপর নির্ভর করে যা তুলনামূলকভাবে নতুন।

উপরের কোড স্নিপেটগুলি আপনার সমস্ত প্রশ্নের উত্তর না দিলে দয়া করে রানযোগ্য প্রকল্পটি দেখুন


23

আপনি রিডেক্স-থাঙ্ক দিয়ে এটি করতে পারেন । সেটটাইমআউটের মতো অ্যাসিঙ্ক ক্রিয়াকলাপের জন্য রিডুএক্স ডকুমেন্টে একটি গাইড রয়েছে


মিডলওয়্যারটি ব্যবহার করার সময় আপনি কেবলমাত্র একটি ফলোআপ প্রশ্ন, applyMiddleware(ReduxPromise, thunk)(createStore)আপনি বেশ কয়েকটি মিডলওয়্যারের (কোমা পৃথকীকরণ?) যুক্ত করার কারণে এটি বোধ হয় না বলে আমি কাজ করতে চাইছি।
ইলজা

1
@ ইলজা এটি কাজ করা উচিত:const store = createStore(reducer, applyMiddleware([ReduxPromise, thunk]));
প্রতিভা

22

আমি এসএএম প্যাটার্নটি একবার দেখে নেওয়ার পরামর্শ দেব ।

এসএএম প্যাটার্নটি "নেক্সট-অ্যাকশন-প্রিকিকেট" অন্তর্ভুক্ত করার জন্য অ্যাডভোকেট যেখানে মডেলটি আপডেট হওয়ার সাথে সাথে "বিজ্ঞপ্তিগুলি 5 সেকেন্ডের পরে স্বয়ংক্রিয়ভাবে অদৃশ্য হয়ে যায়" যেখানে (স্বয়ংক্রিয়) ক্রিয়াকলাপগুলি ট্রিগার করা হয় (এসএএম মডেল ~ রিডুসার স্টেট + স্টোর)।

প্যাটার্নটি একবারে ক্রমানুসারে ক্রিয়াকলাপ এবং মডেল রূপান্তরগুলির জন্য সমর্থন করে, কারণ মডেলটির "নিয়ন্ত্রণ অবস্থা" "নিয়ন্ত্রণ করে" যা ক্রিয়াগুলি সক্ষম হয় এবং / অথবা পরবর্তী ক্রিয়াকলাপ দ্বারা স্বয়ংক্রিয়ভাবে সম্পাদিত হয়। কোনও ক্রিয়া প্রক্রিয়াকরণের আগে সিস্টেমটি কী অবস্থায় থাকবে এবং আপনার পরবর্তী প্রত্যাশিত ক্রিয়া অনুমোদিত / সম্ভব হবে কিনা তা আপনি সহজেই (সাধারণভাবে) ভবিষ্যদ্বাণী করতে পারবেন না।

উদাহরণস্বরূপ কোড,

export function showNotificationWithTimeout(dispatch, text) {
  const id = nextNotificationId++
  dispatch(showNotification(id, text))

  setTimeout(() => {
    dispatch(hideNotification(id))
  }, 5000)
}

এসএএম-এর সাথে অনুমতি দেওয়া হবে না, কারণ একটি হাইডনোটিকেশন অ্যাকশন প্রেরণ করা যেতে পারে তা "শো নোটিকেশন: সত্য" মানটি সফলভাবে গ্রহণ করা মডেলের উপর নির্ভরশীল। মডেলের অন্যান্য অংশ থাকতে পারে যা এটিকে গ্রহণ করতে বাধা দেয় এবং তাই, হাইডনোটিকেশন অ্যাকশনটি ট্রিগার করার কোনও কারণ থাকবে না।

আমি অত্যন্ত সুপারিশ করব যে স্টোর আপডেটগুলি এবং মডেলের নতুন নিয়ন্ত্রণের পরিস্থিতি জানা যাওয়ার পরে একটি যথাযথ পরবর্তী-অ্যাকশন প্রাকিকেট বাস্তবায়ন করুন। আপনি যে আচরণটি সন্ধান করছেন তা বাস্তবায়নের জন্য এটি সবচেয়ে নিরাপদ উপায়।

আপনি চাইলে গিটারে আমাদের সাথে যোগ দিতে পারেন। এখানে একটি এসএএম শুরু করার গাইডও পাওয়া যায়


আমি কেবল এ পর্যন্ত পৃষ্ঠটি স্ক্র্যাচ করেছি, তবে এসএএম প্যাটার্ন দ্বারা ইতিমধ্যে শিহরিত। V = S( vm( M.present( A(data) ) ), nap(M))শুধু সুন্দর। আপনার চিন্তা ও অভিজ্ঞতা ভাগ করে নেওয়ার জন্য ধন্যবাদ। আমি আরও গভীর খনন করব।

@ ফোর, আপনাকে ধন্যবাদ! যখন আমি প্রথমবার এটি লিখেছিলাম, আমারও একই অনুভূতি হয়েছিল। আমি এখন প্রায় এক বছর ধরে উত্পাদনে এসএএম ব্যবহার করেছি এবং আমি এমন একটি সময় ভাবতে পারি না যেখানে আমার মনে হয়েছিল এসএএম বাস্তবায়নের জন্য আমার একটি গ্রন্থাগার দরকার (এমনকি ভোম, যদিও এটি কখন ব্যবহার হতে পারে তা দেখতে পাচ্ছি)। কোডের এক লাইন, এটাই! এসএএম আইসোমোরফিক কোড তৈরি করে, অস্পষ্ট কলগুলির সাথে কীভাবে ডিল করতে হবে এমন কোনও অস্পষ্টতা নেই ... আমি এমন কোনও সময়ের কথা ভাবতে পারি না যেখানে আমি যদিও করছি, আমি কী করছি?
metaprogrammer

এসএএম একটি সত্যিকারের সফ্টওয়্যার ইঞ্জিনিয়ারিং প্যাটার্ন (এটি সবেমাত্র একটি আলেক্সা এসডিকে তৈরি করেছে)। এটি টিএলএ + এর উপর ভিত্তি করে এবং প্রতিটি বিকাশকারীকে সেই অবিশ্বাস্য কাজের শক্তি আনার চেষ্টা করে। এসএএম তিনটি অনুমানকে সংশোধন করে যা (দশমিক এক বছর) প্রত্যেকে দশক ধরে ব্যবহার করে আসছে: - ক্রিয়াগুলি অ্যাপ্লিকেশনের রাজ্যে হস্তক্ষেপ করতে পারে - অ্যাসাইনমেন্টগুলি মিউটেশনের সমতুল্য - কোনও প্রোগ্রামিং পদক্ষেপ কী তার কোনও সঠিক সংজ্ঞা নেই (যেমন একটি = খ * সিএ পদক্ষেপ) , 1 / পঠিত খ, সি 2 / গণনা বি * সি, 3 / ফলাফলকে তিনটি ভিন্ন ধাপে বরাদ্দ করুন?
রূপান্তরকামী

20

বিভিন্ন জনপ্রিয় পদ্ধতির (ক্রিয়া স্রষ্টা, থঙ্কস, সাগাস, মহাকাব্যগুলি, প্রভাবগুলি, কাস্টম মিডলওয়্যার) চেষ্টা করার পরেও আমি এখনও অনুভব করেছি যে উন্নতির কোনও জায়গা রয়েছে তাই আমি এই ব্লগ নিবন্ধটিতে আমার যাত্রাটি নথিভুক্ত করেছি, যেখানে আমি আমার ব্যবসায়িক যুক্তি রেখেছি একটি প্রতিক্রিয়া / Redux অ্যাপ্লিকেশন?

এখানে আলোচনার মতো, আমি বিভিন্ন পদ্ধতির বিপরীতে তুলনা করার চেষ্টা করেছি। শেষ পর্যন্ত এটি আমাকে একটি নতুন লাইব্রেরি রিডেক্স-লজিক প্রবর্তন করতে পরিচালিত করেছিল যা মহাকাব্য, সাগাস, কাস্টম মিডলওয়্যার থেকে অনুপ্রেরণা গ্রহণ করে।

এটি আপনাকে বৈধতা যাচাইকরণ, যাচাইকরণ, অনুমোদন দেওয়ার পাশাপাশি অ্যাসিঙ্ক আইও সম্পাদন করার উপায় সরবরাহ করার অনুমতি দেয়।

কিছু সাধারণ কার্যকারিতা কেবল ঘোষিত, থ্রোল্টলিং, বাতিলকরণ এবং কেবল সর্বশেষতম অনুরোধের (টেকলাইটেস্ট) প্রতিক্রিয়া ব্যবহার করার মতো ঘোষণা করা যেতে পারে। রিডেক্স-লজিক আপনার কোডটিকে আপনার জন্য এই কার্যকারিতা সরবরাহ করে ps

এটি আপনাকে পছন্দ করে তবে আপনার মূল ব্যবসায়ের যুক্তি বাস্তবায়নে মুক্তি দেয়। আপনি না চাইলে আপনাকে পর্যবেক্ষণযোগ্য বা জেনারেটর ব্যবহার করতে হবে না। ফাংশন এবং কলব্যাক, প্রতিশ্রুতি, অ্যাসিঙ্ক ফাংশন (অ্যাসিঙ্ক / অপেক্ষা) ইত্যাদি ব্যবহার করুন

একটি সাধারণ 5s বিজ্ঞপ্তি করার কোডটি এরকম হবে:

const notificationHide = createLogic({
  // the action type that will trigger this logic
  type: 'NOTIFICATION_DISPLAY',
  
  // your business logic can be applied in several
  // execution hooks: validate, transform, process
  // We are defining our code in the process hook below
  // so it runs after the action hit reducers, hide 5s later
  process({ getState, action }, dispatch) {
    setTimeout(() => {
      dispatch({ type: 'NOTIFICATION_CLEAR' });
    }, 5000);
  }
});
    

আমার রেপোতে আমার আরও উন্নত বিজ্ঞপ্তির উদাহরণ রয়েছে যা সেবাস্তিয়ান লোরবারের বর্ণনার সাথে একই রকম কাজ করে যেখানে আপনি ডিসপ্লেটিকে এন আইটেমে সীমাবদ্ধ করতে এবং যে কোনও সারিবদ্ধভাবে ঘোরান। রিডেক্স-লজিক বিজ্ঞপ্তির উদাহরণ

আমার কাছে বিভিন্ন ধরণের রিডেক্স-লজিক jsfiddle লাইভ উদাহরণ রয়েছে পাশাপাশি পুরো উদাহরণ । আমি ডক্স এবং উদাহরণগুলিতে কাজ চালিয়ে যাচ্ছি।

আমি আপনার মতামত শুনতে পছন্দ করি।


আমি নিশ্চিত যে আমি আপনার লাইব্রেরি পছন্দ করি তবে আমি আপনার নিবন্ধটি পছন্দ করি! ভাল হয়েছে, মানুষ! অন্যের সময় বাঁচানোর জন্য আপনি যথেষ্ট কাজ করেছেন।
টাইলার দীর্ঘ

2
আমি এখানে রিডেক্স -লজিকের জন্য একটি নমুনা প্রকল্প তৈরি করেছি: github.com/tylerlong/hello-async/tree/master/redux-logic আমি মনে করি এটি একটি ভাল ডিজাইনের সফ্টওয়্যার এবং আমি অন্যের তুলনায় কোনও বড় অসুবিধা দেখতে পাচ্ছি না বিকল্প।
টাইলার দীর্ঘ

9

আমি বুঝতে পারি যে এই প্রশ্নটি কিছুটা পুরাতন তবে আমি হ্রাস-পর্যবেক্ষণযোগ্য ওরফে ব্যবহার করে আরও একটি সমাধান আনতে যাচ্ছি । এপিক।

অফিসিয়াল ডকুমেন্টেশন উদ্ধৃত:

রিডেক্স-পর্যবেক্ষণযোগ্য কী?

রেডাক্সের জন্য আরএক্সজেএস 5-ভিত্তিক মিডলওয়্যার। পার্শ্ব প্রতিক্রিয়া এবং আরও অনেক কিছু তৈরি করতে async ক্রিয়া রচনা করুন এবং বাতিল করুন।

একটি এপিক হ'ল রিডেক্স-পর্যবেক্ষণের মূল আদিম।

এটি এমন একটি ফাংশন যা ক্রিয়াগুলির একটি স্ট্রিম গ্রহণ করে এবং ক্রিয়াকলাপের একটি স্ট্রিম প্রদান করে। ক্রিয়াগুলি, ক্রিয়াগুলি আউট।

আরও কম শব্দে, আপনি একটি ফাংশন তৈরি করতে পারেন যা কোনও স্ট্রিমের মাধ্যমে ক্রিয়া গ্রহণ করে এবং তারপরে ক্রিয়াগুলির একটি নতুন স্ট্রিম (টাইমআউটস, বিলম্ব, বিরতি এবং অনুরোধগুলির মতো সাধারণ পার্শ্ব প্রতিক্রিয়াগুলি ব্যবহার করে) ফিরে আসতে পারে।

আমাকে কোড পোস্ট করুন এবং তারপরে আরও কিছুটা ব্যাখ্যা করুন

store.js

import {createStore, applyMiddleware} from 'redux'
import {createEpicMiddleware} from 'redux-observable'
import {Observable} from 'rxjs'
const NEW_NOTIFICATION = 'NEW_NOTIFICATION'
const QUIT_NOTIFICATION = 'QUIT_NOTIFICATION'
const NOTIFICATION_TIMEOUT = 2000

const initialState = ''
const rootReducer = (state = initialState, action) => {
  const {type, message} = action
  console.log(type)
  switch(type) {
    case NEW_NOTIFICATION:
      return message
    break
    case QUIT_NOTIFICATION:
      return initialState
    break
  }

  return state
}

const rootEpic = (action$) => {
  const incoming = action$.ofType(NEW_NOTIFICATION)
  const outgoing = incoming.switchMap((action) => {
    return Observable.of(quitNotification())
      .delay(NOTIFICATION_TIMEOUT)
      //.takeUntil(action$.ofType(NEW_NOTIFICATION))
  });

  return outgoing;
}

export function newNotification(message) {
  return ({type: NEW_NOTIFICATION, message})
}
export function quitNotification(message) {
  return ({type: QUIT_NOTIFICATION, message});
}

export const configureStore = () => createStore(
  rootReducer,
  applyMiddleware(createEpicMiddleware(rootEpic))
)

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {configureStore} from './store.js'
import {Provider} from 'react-redux'

const store = configureStore()

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

App.js

import React, { Component } from 'react';
import {connect} from 'react-redux'
import {newNotification} from './store.js'

class App extends Component {

  render() {
    return (
      <div className="App">
        {this.props.notificationExistance ? (<p>{this.props.notificationMessage}</p>) : ''}
        <button onClick={this.props.onNotificationRequest}>Click!</button>
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  return {
    notificationExistance : state.length > 0,
    notificationMessage : state
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onNotificationRequest: () => dispatch(newNotification(new Date().toDateString()))
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

এই সমস্যাটি সমাধানের মূল কোডটি পাই হিসাবে দেখতে পারাও সহজ, কেবলমাত্র অন্য উত্তরগুলির থেকে পৃথক প্রদর্শিত জিনিসটি হ'ল ফাংশন রুটপিক।

পয়েন্ট 1. সাগাসের মতো, আপনাকে একটি শীর্ষ স্তরের ফাংশন পেতে ক্রিয়াকলাপগুলি একত্রিত করতে হবে যা ক্রিয়াগুলির স্ট্রিম গ্রহণ করে এবং ক্রিয়াগুলির একটি স্ট্রিম ফিরিয়ে দেয়, যাতে আপনি এটি মিডলওয়্যার কারখানা তৈরির অ্যাপিকমিডলওয়্যারের সাথে ব্যবহার করতে পারেন । আমাদের ক্ষেত্রে আমাদের কেবল একটি প্রয়োজন তাই আমাদের কেবল আমাদের রুটপিক থাকে তাই আমাদের কোনও কিছুর সংমিশ্রণ করতে হবে না তবে সত্যটি জানা ভাল।

পয়েন্ট ২. আমাদের রুটপিক যা পার্শ্ব প্রতিক্রিয়া যুক্তির বিষয়ে যত্ন নিয়েছে কেবলমাত্র 5 টি লাইনের কোড লাগে যা দুর্দান্ত! বাস্তব সহ বেশ কয়েকটি ঘোষণামূলক!

পয়েন্ট 3. লাইন রুট ইপিক ব্যাখ্যা দ্বারা রেখা (মন্তব্যে)

const rootEpic = (action$) => {
  // sets the incoming constant as a stream 
  // of actions with  type NEW_NOTIFICATION
  const incoming = action$.ofType(NEW_NOTIFICATION)
  // Merges the "incoming" stream with the stream resulting for each call
  // This functionality is similar to flatMap (or Promise.all in some way)
  // It creates a new stream with the values of incoming and 
  // the resulting values of the stream generated by the function passed
  // but it stops the merge when incoming gets a new value SO!,
  // in result: no quitNotification action is set in the resulting stream
  // in case there is a new alert
  const outgoing = incoming.switchMap((action) => {
    // creates of observable with the value passed 
    // (a stream with only one node)
    return Observable.of(quitNotification())
      // it waits before sending the nodes 
      // from the Observable.of(...) statement
      .delay(NOTIFICATION_TIMEOUT)
  });
  // we return the resulting stream
  return outgoing;
}

আমি আসা করি এটা সাহায্য করবে!


নির্দিষ্ট এপি পদ্ধতিগুলি এখানে কী করছে তা আপনি ব্যাখ্যা করতে পারেন, যেমন switchMap?
দিমিত্রি জইতসেভ

1
আমরা উইন্ডোজটিতে আমাদের রিএ্যাক্ট নেটিভ অ্যাপ্লিকেশনটিতে হ্রাস-পর্যবেক্ষণযোগ্য ব্যবহার করছি। এটি একটি জটিল, অত্যন্ত অ্যাসিনক্রোনাস সমস্যার একটি মার্জিত বাস্তবায়ন সমাধান এবং তাদের জিটার চ্যানেল এবং গিটহাব ইস্যুগুলির মাধ্যমে দুর্দান্ত সমর্থন রয়েছে। জটিলতার অতিরিক্ত স্তরটি কেবল তখনই মূল্যবান যখন আপনি ঠিক সমস্যাটি সমাধান করতে চাইছেন ঠিক অবশ্যই পৌঁছেছেন।
ম্যাট হার্জেট

8

কেন এত কঠিন হওয়া উচিত? এটি কেবল ইউআই যুক্তিযুক্ত। বিজ্ঞপ্তি ডেটা সেট করতে একটি নিবেদিত ক্রিয়া ব্যবহার করুন:

dispatch({ notificationData: { message: 'message', expire: +new Date() + 5*1000 } })

এবং এটি প্রদর্শনের জন্য একটি উত্সর্গীকৃত উপাদান:

const Notifications = ({ notificationData }) => {
    if(notificationData.expire > this.state.currentTime) {
      return <div>{notificationData.message}</div>
    } else return null;
}

এই ক্ষেত্রে প্রশ্নগুলি "আপনি কীভাবে পুরানো অবস্থা পরিষ্কার করবেন?", "সেই সময়ের পরিবর্তিত কোনও উপাদানকে কীভাবে सूचित করবেন" হওয়া উচিত

আপনি কিছু TIMEOUT ক্রিয়া বাস্তবায়ন করতে পারেন যা একটি উপাদান থেকে সেটটাইমআউটে প্রেরণ করা হয়েছে।

যখনই কোনও নতুন বিজ্ঞপ্তি প্রদর্শিত হবে তখন এটি পরিষ্কার করা ঠিক।

যাইহোক, কিছু setTimeoutকোথাও থাকা উচিত , তাই না? কেন এটি একটি উপাদান না

setTimeout(() => this.setState({ currentTime: +new Date()}), 
           this.props.notificationData.expire-(+new Date()) )

অনুপ্রেরণা হ'ল "নোটিফিকেশন ফেইড আউট" কার্যকারিতা আসলে একটি ইউআই উদ্বেগ। সুতরাং এটি আপনার ব্যবসায়িক যুক্তির জন্য পরীক্ষা সহজতর করে।

এটি কীভাবে বাস্তবায়ন হয়েছে তা পরীক্ষা করে দেখার মতো মনে হয় না। বিজ্ঞপ্তিটি কখন শেষ হবে তা যাচাই করে তা বোধগম্য। এইভাবে স্টব কম কোড, দ্রুত পরীক্ষা, ক্লিনার কোড।


1
এটি শীর্ষ উত্তর হওয়া উচিত।
এমএমলা

6

আপনি যদি নির্বাচক ক্রিয়াকলাপের সময়সীমা হ্যান্ডলিং করতে চান তবে আপনি মিডলওয়্যারটি চেষ্টা করতে পারেন পদ্ধতির । প্রতিশ্রুতি ভিত্তিক ক্রিয়াগুলি নির্বাচন করে পরিচালনা করার জন্য আমি একই ধরণের সমস্যার মুখোমুখি হয়েছিলাম এবং এই সমাধানটি আরও নমনীয় ছিল।

আপনাকে বলি যে আপনার অ্যাকশন নির্মাতাকে এইরকম দেখাচ্ছে:

//action creator
buildAction = (actionData) => ({
    ...actionData,
    timeout: 500
})

সময়সীমা উপরের ক্রিয়ায় একাধিক মান ধরে রাখতে পারে

  • এমএসে নম্বর - একটি নির্দিষ্ট সময়সীমা জন্য
  • সত্য - একটি ধ্রুবক সময়সীমা জন্য। (মিডওয়্যারের মধ্যে পরিচালিত)
  • অপরিবর্তিত - তাত্ক্ষণিক প্রেরণের জন্য

আপনার মিডলওয়্যার বাস্তবায়নটি দেখতে এরকম হবে:

//timeoutMiddleware.js
const timeoutMiddleware = store => next => action => {

  //If your action doesn't have any timeout attribute, fallback to the default handler
  if(!action.timeout) {
    return next (action)
  }

  const defaultTimeoutDuration = 1000;
  const timeoutDuration = Number.isInteger(action.timeout) ? action.timeout || defaultTimeoutDuration;

//timeout here is called based on the duration defined in the action.
  setTimeout(() => {
    next (action)
  }, timeoutDuration)
}

আপনি এখন মিডলওয়্যার স্তরটি রিডুএক্স ব্যবহার করে আপনার সমস্ত ক্রিয়া রুট করতে পারেন।

createStore(reducer, applyMiddleware(timeoutMiddleware))

আপনি এখানে কিছু অনুরূপ উদাহরণ খুঁজে পেতে পারেন


5

এটি করার উপযুক্ত উপায় হ'ল রেডাক্স থাঙ্ক ব্যবহার করা যা রেডাক্স থঙ্ক ডকুমেন্টেশন অনুসারে রেডাক্সের জন্য একটি জনপ্রিয় মিডলওয়্যার:

"রেডাক্স থাঙ্ক মিডলওয়্যার আপনাকে অ্যাকশন স্রষ্টাদের লেখার অনুমতি দেয় যা কোনও অ্যাকশনের পরিবর্তে কোনও ফাংশন ফিরিয়ে দেয় th থাঙ্কটি কোনও ক্রিয়াকলাপ প্রেরণে বিলম্ব করতে বা কোনও নির্দিষ্ট শর্ত পূরণ করা হলে কেবল প্রেরণে ব্যবহার করা যেতে পারে inner অভ্যন্তরীণ ফাংশনটি স্টোরের পদ্ধতিগুলি গ্রহণ করে পরামিতি হিসাবে প্রেরণ এবং getState "।

সুতরাং মূলত এটি কোনও ফাংশন ফিরিয়ে দেয় এবং আপনি আপনার প্রেরণে বিলম্ব করতে বা এটি একটি অবস্থায় রাখতে পারেন।

সুতরাং এর মতো কিছু আপনার জন্য কাজটি করতে চলেছে:

import ReduxThunk from 'redux-thunk';

const INCREMENT_COUNTER = 'INCREMENT_COUNTER';

function increment() {
  return {
    type: INCREMENT_COUNTER
  };
}

function incrementAsync() {
  return dispatch => {
    setTimeout(() => {
      // Yay! Can invoke sync or async actions with `dispatch`
      dispatch(increment());
    }, 5000);
  };
}

4

এটা সহজ. ব্যবহার করুন ট্রিম-redux মধ্যে প্যাকেজ এবং এমন একটি লেখার componentDidMountবা অন্যান্য জায়গা এবং এটি হত্যা componentWillUnmount

componentDidMount() {
  this.tm = setTimeout(function() {
    setStore({ age: 20 });
  }, 3000);
}

componentWillUnmount() {
  clearTimeout(this.tm);
}

3

রেডাক্স নিজেই একটি সুন্দর ভার্জোজ লাইব্রেরি, এবং এই জাতীয় জিনিসগুলির জন্য আপনাকে রেডাক্স-থাঙ্কের মতো কিছু ব্যবহার করতে হবে যা একটি dispatchফাংশন দেবে, তাই আপনি কয়েক সেকেন্ড পরে বিজ্ঞপ্তিটি বন্ধ করে পাঠাতে সক্ষম হবেন।

ভারবোসিটি এবং কমপোসিবিলিটির মতো সমস্যাগুলি সমাধান করার জন্য আমি একটি গ্রন্থাগার তৈরি করেছি এবং আপনার উদাহরণ নীচের মত দেখাবে:

import { createTile, createSyncTile } from 'redux-tiles';
import { sleep } from 'delounce';

const notifications = createSyncTile({
  type: ['ui', 'notifications'],
  fn: ({ params }) => params.data,
  // to have only one tile for all notifications
  nesting: ({ type }) => [type],
});

const notificationsManager = createTile({
  type: ['ui', 'notificationManager'],
  fn: ({ params, dispatch, actions }) => {
    dispatch(actions.ui.notifications({ type: params.type, data: params.data }));
    await sleep(params.timeout || 5000);
    dispatch(actions.ui.notifications({ type: params.type, data: null }));
    return { closed: true };
  },
  nesting: ({ type }) => [type],
});

সুতরাং আমরা async ক্রিয়াকলাপের মধ্যে বিজ্ঞপ্তিগুলি দেখানোর জন্য সিঙ্ক ক্রিয়াগুলি রচনা করি, যা কিছু তথ্য পটভূমির জন্য অনুরোধ করতে পারে বা বিজ্ঞপ্তিটি ম্যানুয়ালি বন্ধ করা হয়েছে কিনা তা পরে পরীক্ষা করতে পারেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.