ফ্লাক্স আর্কিটেকচারে, আপনি কীভাবে স্টোর লাইফাইসাইকেল পরিচালনা করবেন?


132

আমি ফ্লাক্স সম্পর্কে পড়ছি তবে টোডো অ্যাপ্লিকেশনটি আমার কাছে কিছু মূল বিষয়গুলি বোঝার জন্য খুব সরল।

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

ফ্লাক্স আর্কিটেকচারে, এটি কীভাবে স্টোর এবং প্রেরণকারীদের সাথে সামঞ্জস্য করবে?

আমরা কি PostStoreব্যবহারকারীর জন্য একটি ব্যবহার করব , বা আমাদের কোনও ধরণের গ্লোবাল স্টোর থাকবে? প্রেরণকারীদের কী, আমরা প্রতিটি "ব্যবহারকারী পৃষ্ঠা" এর জন্য একটি নতুন ডিসপ্যাচার তৈরি করব, বা আমরা একটি সিঙ্গলটন ব্যবহার করব? অবশেষে, রুটের পরিবর্তনের প্রতিক্রিয়ায় "পৃষ্ঠা-নির্দিষ্ট" স্টোরগুলির জীবনকাল পরিচালনা করার জন্য আর্কিটেকচারের কোন অংশটি দায়বদ্ধ?

তদুপরি, একটি একক সিউডো-পৃষ্ঠায় একই ধরণের ডেটার কয়েকটি তালিকা থাকতে পারে। উদাহরণস্বরূপ, একটি প্রোফাইল পৃষ্ঠায়, আমি অনুসরণকারী এবং অনুসরণ উভয়ই দেখতে চাই । UserStoreএই ক্ষেত্রে একটি সিঙ্গলটন কীভাবে কাজ করতে পারে? চান UserPageStoreপরিচালনা followedBy: UserStoreএবং follows: UserStore?

উত্তর:


124

একটি ফ্লাক্স অ্যাপে কেবলমাত্র একজন ডিসপ্যাচার থাকতে হবে be সমস্ত ডেটা এই কেন্দ্রীয় হাবের মধ্য দিয়ে প্রবাহিত হয়। একটি সিঙ্গলটন ডিসপ্যাচার থাকলে এটি সমস্ত স্টোর পরিচালনা করতে দেয় manage এটি গুরুত্বপূর্ণ হয়ে ওঠে যখন আপনার প্রয়োজন হয় স্টোর # 1 আপডেট নিজেই, এবং তারপরে স্টোর # 2 আপডেট নিজেই ক্রিয়াকলাপ এবং স্টোর # 1 এর স্থিতির ভিত্তিতে have ফ্লাক্স ধরে নেয় যে এই পরিস্থিতি একটি বৃহত প্রয়োগের ক্ষেত্রে একটি পরিণতি। আদর্শভাবে এই পরিস্থিতি হওয়ার দরকার হবে না, এবং যদি সম্ভব হয় তবে বিকাশকারীদের এই জটিলতা এড়াতে চেষ্টা করা উচিত। তবে সিঙ্গলটন ডিসপ্যাচার যখন সময় আসবে তখন এটি পরিচালনা করতে প্রস্তুত।

স্টোরগুলি পাশাপাশি সিলেটলেটস। এগুলি যথাসম্ভব স্বতন্ত্র এবং ডৌপলড থাকা উচিত - একটি স্বনির্ভর মহাবিশ্ব যা নিয়ামক-দর্শন থেকে প্রশ্ন করতে পারে। স্টোরের একমাত্র রাস্তা কলব্যাকের মাধ্যমে এটি ডিসপ্যাচারের সাথে নিবন্ধিত হয়। গেটর ফাংশনগুলির মাধ্যমে একমাত্র রাস্তা। স্টোরগুলি যখন তাদের রাজ্য পরিবর্তিত হয় তখন একটি ইভেন্টও প্রকাশ করে, তাই কন্ট্রোলার-ভিউগুলি কখন নতুন রাষ্ট্রের জন্য কোয়েরি করতে হবে তা জানতে পারে get

আপনার উদাহরণ অ্যাপ্লিকেশন, একটি একক হবে PostStore। এই একই স্টোরটি "পৃষ্ঠায়" (সিউডো পৃষ্ঠা) পোস্টগুলি পরিচালনা করতে পারে যা এফবির নিউজফিডের মতো, যেখানে বিভিন্ন ব্যবহারকারীদের পোস্ট প্রকাশিত হয়। এটির যৌক্তিক ডোমেন হ'ল পোস্টগুলির তালিকা এবং এটি পোস্টের যে কোনও তালিকা পরিচালনা করতে পারে। যখন আমরা সিউডো-পৃষ্ঠা থেকে সিউডো-পৃষ্ঠায় চলে যাই, আমরা নতুন অবস্থার প্রতিফলন করতে স্টোরের রাজ্যটিকে পুনরায় নতুন করে দিতে চাই। সিউডো-পৃষ্ঠাগুলির মধ্যে পিছনে এগিয়ে যাওয়ার অপ্টিমাইজেশন হিসাবে আমরা স্থানীয় স্টোরেজে পূর্বের অবস্থাটি ক্যাশে করতে চাইব, তবে আমার প্রবণতাটি এমন একটি সেট আপ করা PageStoreহবে যা অন্য সমস্ত স্টোরের জন্য অপেক্ষা করে, সমস্ত স্টোরের জন্য স্থানীয় স্টোরের সাথে সম্পর্ক পরিচালনা করে on সিউডো-পৃষ্ঠা এবং তারপরে তার নিজস্ব অবস্থা আপডেট করে। নোট করুন যে PageStoreএটি পোস্টগুলি সম্পর্কে কিছুই সঞ্চয় করবে না - এটিই এর ডোমেনPostStore। এটি কেবল সহজেই জানতে পারে যে কোনও নির্দিষ্ট সিউডো-পৃষ্ঠা ক্যাশে হয়েছে কি না, কারণ সিউডো-পৃষ্ঠাগুলি এর ডোমেন।

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

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


5
আপনি যা করতে চান তার জন্য অবশ্যই কয়েকটি পৃথক পন্থা রয়েছে এবং আমি মনে করি এটি আপনি কী তৈরির চেষ্টা করছেন তার উপর নির্ভর করে। এর মধ্যে UserListStoreসমস্ত প্রাসঙ্গিক ব্যবহারকারীদের সাথে একটি পন্থা হবে । এবং প্রতিটি ব্যবহারকারীর বর্তমান ব্যবহারকারী প্রোফাইলের সাথে সম্পর্কের বর্ণনা দেওয়ার জন্য বেশ কয়েকটি বুলিয়ান পতাকা থাকবে। { follower: true, followed: false }যেমন কিছু উদাহরণ। পদ্ধতিগুলি getFolloweds()এবং getFollowers()আপনার ইউআইয়ের জন্য প্রয়োজনীয় ব্যবহারকারীদের বিভিন্ন সেট পুনরুদ্ধার করবে।
মৎস্যবিদেব

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

আমার একটি ছোট প্রশ্ন আছে - কেন গ্রাহকরা ডেটা পুনরুদ্ধারের প্রয়োজনের চেয়ে সরাসরি স্টোর থেকে ডেটা নির্গত করতে পাব সাব ব্যবহার করবেন না?
সূরওয়ুকুং

2
@ সানওয়ুকুং এর জন্য স্টোরগুলিতে নিয়ামক-দর্শনগুলির জন্য কোন ডেটা প্রয়োজন তা ট্র্যাক করে রাখতে হবে। স্টোরগুলি কোনও উপায়ে পরিবর্তিত হয়েছে এই বিষয়টি প্রকাশ করার জন্য এটি পরিষ্কার এবং তারপরে আগ্রহী নিয়ামক-দর্শনগুলি তাদের প্রয়োজনীয় ডেটার অংশগুলি পুনরুদ্ধার করতে দিন।
ফিশারদেবদেব

আমার যদি এমন একটি প্রোফাইল পৃষ্ঠা থাকে যেখানে আমি কোনও ব্যবহারকারী সম্পর্কে তথ্য দেখাই তবে তার বন্ধুদের তালিকাও থাকি। ব্যবহারকারী এবং বন্ধু উভয়ই একই ধরণের হবে। তাদের কি একই দোকানে থাকা উচিত?
নিক দীমা

79

(দ্রষ্টব্য: আমি জেএসএক্স হারমনি বিকল্পটি ব্যবহার করে ES6 সিনট্যাক্স ব্যবহার করেছি))

অনুশীলন হিসাবে, আমি একটি নমুনা ফ্লাক্স অ্যাপ্লিকেশন লিখেছিলাম যা ব্রাউজ Github usersএবং পুনরায় পোস্ট করতে দেয় ।
এটি ফিশারভেদেবদের উত্তরের উপর ভিত্তি করে তৈরি করা হয়েছে তবে এপিআই প্রতিক্রিয়াগুলিকে স্বাভাবিক করার জন্য আমি ব্যবহার করা একটি পদ্ধতির প্রতিফলনও ঘটায়।

ফ্লাক্স শেখার সময় আমি চেষ্টা করেছি এমন কয়েকটি পদ্ধতির নথিতে এটি তৈরি করেছি made
আমি এটিকে বাস্তব বিশ্বের কাছে রাখার চেষ্টা করেছি (পৃষ্ঠাগুলি, কোনও ভুয়া লোকালস্টোর এপিআই) নেই।

এখানে কয়েকটি বিট রয়েছে যার মধ্যে আমি বিশেষভাবে আগ্রহী:

আমি কীভাবে স্টোরকে শ্রেণিবদ্ধ করি

আমি অন্যান্য ফ্লুक्स উদাহরণগুলিতে, বিশেষত স্টোরগুলিতে দেখেছি এমন কয়েকটি সদৃশ এড়াতে চেষ্টা করেছি। আমি যৌক্তিকভাবে স্টোরগুলিকে তিনটি বিভাগে বিভক্ত করা দরকারী বলে মনে করেছি:

সামগ্রী স্টোরগুলিতে সমস্ত অ্যাপ সত্তা থাকে। আইডি থাকা প্রত্যেকটির নিজস্ব সামগ্রী স্টোর দরকার needs উপাদানগুলি যা পৃথক আইটেম সরবরাহ করে তা নতুন সামগ্রীর জন্য সামগ্রী স্টোরকে জিজ্ঞাসা করে।

সামগ্রী স্টোরগুলি সমস্ত সার্ভার ক্রিয়াকলাপ থেকে তাদের জিনিসগুলি সংগ্রহ করে harvest উদাহরণস্বরূপ, UserStore মধ্যে দেখায়action.response.entities.users যদি উপস্থিত থাকে নির্বিশেষে যার কর্ম বহিস্কার। কোন প্রয়োজন নেই switchনরমালিজার এই ফর্ম্যাটটিতে কোনও API প্রতিক্রিয়াগুলি সমতল করা সহজ করে তোলে।

// Content Stores keep their data like this
{
  7: {
    id: 7,
    name: 'Dan'
  },
  ...
}

তালিকা স্টোরগুলি কিছু বিশ্বব্যাপী তালিকায় উপস্থিত সত্ত্বার আইডিগুলির নজর রাখে (যেমন "ফিড", "আপনার বিজ্ঞপ্তি")। এই প্রকল্পে, আমার কাছে এই জাতীয় স্টোর নেই তবে আমি ভেবেছিলাম যে আমি সেগুলি যেভাবেই উল্লেখ করব। তারা পৃষ্ঠাগুলি পরিচালনা করে।

তারা সাধারণত মাত্র কয়েক ক্রিয়া সাড়া (যেমন REQUEST_FEED, REQUEST_FEED_SUCCESS, REQUEST_FEED_ERROR)।

// Paginated Stores keep their data like this
[7, 10, 5, ...]

ইনডেক্সযুক্ত তালিকার স্টোরগুলি তালিকার স্টোরগুলির মতো তবে তারা একের সাথে একাধিক সম্পর্কের সংজ্ঞা দেয়। উদাহরণস্বরূপ, "ব্যবহারকারীর গ্রাহকগণ", "সংগ্রহস্থলের স্টারগাজার", "ব্যবহারকারীর সংগ্রহশালা"। তারা পৃষ্ঠাগুলিও পরিচালনা করে।

তারা সাধারণত মাত্র কয়েক ক্রিয়া সাড়া (যেমন REQUEST_USER_REPOS, REQUEST_USER_REPOS_SUCCESS, REQUEST_USER_REPOS_ERROR)।

বেশিরভাগ সামাজিক অ্যাপ্লিকেশনগুলিতে, আপনার কাছে এগুলির প্রচুর পরিমাণ রয়েছে এবং আপনি সেগুলির মধ্যে আরও একটি তৈরি করতে সক্ষম হতে চান want

// Indexed Paginated Stores keep their data like this
{
  2: [7, 10, 5, ...],
  6: [7, 1, 2, ...],
  ...
}

দ্রষ্টব্য: এগুলি প্রকৃত শ্রেণি বা কিছু নয়; আমি স্টোর সম্পর্কে ঠিক কীভাবে ভাবতে চাই তা এটি। যদিও আমি কয়েক জন সহায়ক তৈরি করেছি।

StoreUtils

createStore

এই পদ্ধতিটি আপনাকে সর্বাধিক প্রাথমিক স্টোর দেয়:

createStore(spec) {
  var store = merge(EventEmitter.prototype, merge(spec, {
    emitChange() {
      this.emit(CHANGE_EVENT);
    },

    addChangeListener(callback) {
      this.on(CHANGE_EVENT, callback);
    },

    removeChangeListener(callback) {
      this.removeListener(CHANGE_EVENT, callback);
    }
  }));

  _.each(store, function (val, key) {
    if (_.isFunction(val)) {
      store[key] = store[key].bind(store);
    }
  });

  store.setMaxListeners(0);
  return store;
}

আমি এটি সমস্ত স্টোর তৈরি করতে ব্যবহার করি।

isInBag, mergeIntoBag

কন্টেন্ট স্টোরের জন্য দরকারী ছোট সহায়ক

isInBag(bag, id, fields) {
  var item = bag[id];
  if (!bag[id]) {
    return false;
  }

  if (fields) {
    return fields.every(field => item.hasOwnProperty(field));
  } else {
    return true;
  }
},

mergeIntoBag(bag, entities, transform) {
  if (!transform) {
    transform = (x) => x;
  }

  for (var key in entities) {
    if (!entities.hasOwnProperty(key)) {
      continue;
    }

    if (!bag.hasOwnProperty(key)) {
      bag[key] = transform(entities[key]);
    } else if (!shallowEqual(bag[key], entities[key])) {
      bag[key] = transform(merge(bag[key], entities[key]));
    }
  }
}

PaginatedList

পৃষ্ঠাগুলি স্থিতি সংরক্ষণ করে এবং কিছু নির্দিষ্ট দৃser়তা প্রয়োগ করে (আনার সময় পৃষ্ঠা আনতে পারে না ইত্যাদি)।

class PaginatedList {
  constructor(ids) {
    this._ids = ids || [];
    this._pageCount = 0;
    this._nextPageUrl = null;
    this._isExpectingPage = false;
  }

  getIds() {
    return this._ids;
  }

  getPageCount() {
    return this._pageCount;
  }

  isExpectingPage() {
    return this._isExpectingPage;
  }

  getNextPageUrl() {
    return this._nextPageUrl;
  }

  isLastPage() {
    return this.getNextPageUrl() === null && this.getPageCount() > 0;
  }

  prepend(id) {
    this._ids = _.union([id], this._ids);
  }

  remove(id) {
    this._ids = _.without(this._ids, id);
  }

  expectPage() {
    invariant(!this._isExpectingPage, 'Cannot call expectPage twice without prior cancelPage or receivePage call.');
    this._isExpectingPage = true;
  }

  cancelPage() {
    invariant(this._isExpectingPage, 'Cannot call cancelPage without prior expectPage call.');
    this._isExpectingPage = false;
  }

  receivePage(newIds, nextPageUrl) {
    invariant(this._isExpectingPage, 'Cannot call receivePage without prior expectPage call.');

    if (newIds.length) {
      this._ids = _.union(this._ids, newIds);
    }

    this._isExpectingPage = false;
    this._nextPageUrl = nextPageUrl || null;
    this._pageCount++;
  }
}

PaginatedStoreUtils

createListStore, createIndexedListStore,createListActionHandler

বয়লারপ্লেট পদ্ধতি এবং অ্যাকশন হ্যান্ডলিং সরবরাহ করে সূচক তালিকাভুক্ত স্টোরগুলি যথাসম্ভব সহজ করে তোলে:

var PROXIED_PAGINATED_LIST_METHODS = [
  'getIds', 'getPageCount', 'getNextPageUrl',
  'isExpectingPage', 'isLastPage'
];

function createListStoreSpec({ getList, callListMethod }) {
  var spec = {
    getList: getList
  };

  PROXIED_PAGINATED_LIST_METHODS.forEach(method => {
    spec[method] = function (...args) {
      return callListMethod(method, args);
    };
  });

  return spec;
}

/**
 * Creates a simple paginated store that represents a global list (e.g. feed).
 */
function createListStore(spec) {
  var list = new PaginatedList();

  function getList() {
    return list;
  }

  function callListMethod(method, args) {
    return list[method].call(list, args);
  }

  return createStore(
    merge(spec, createListStoreSpec({
      getList: getList,
      callListMethod: callListMethod
    }))
  );
}

/**
 * Creates an indexed paginated store that represents a one-many relationship
 * (e.g. user's posts). Expects foreign key ID to be passed as first parameter
 * to store methods.
 */
function createIndexedListStore(spec) {
  var lists = {};

  function getList(id) {
    if (!lists[id]) {
      lists[id] = new PaginatedList();
    }

    return lists[id];
  }

  function callListMethod(method, args) {
    var id = args.shift();
    if (typeof id ===  'undefined') {
      throw new Error('Indexed pagination store methods expect ID as first parameter.');
    }

    var list = getList(id);
    return list[method].call(list, args);
  }

  return createStore(
    merge(spec, createListStoreSpec({
      getList: getList,
      callListMethod: callListMethod
    }))
  );
}

/**
 * Creates a handler that responds to list store pagination actions.
 */
function createListActionHandler(actions) {
  var {
    request: requestAction,
    error: errorAction,
    success: successAction,
    preload: preloadAction
  } = actions;

  invariant(requestAction, 'Pass a valid request action.');
  invariant(errorAction, 'Pass a valid error action.');
  invariant(successAction, 'Pass a valid success action.');

  return function (action, list, emitChange) {
    switch (action.type) {
    case requestAction:
      list.expectPage();
      emitChange();
      break;

    case errorAction:
      list.cancelPage();
      emitChange();
      break;

    case successAction:
      list.receivePage(
        action.response.result,
        action.response.nextPageUrl
      );
      emitChange();
      break;
    }
  };
}

var PaginatedStoreUtils = {
  createListStore: createListStore,
  createIndexedListStore: createIndexedListStore,
  createListActionHandler: createListActionHandler
};

createStoreMixin

একজন mixin যে স্টোর তারা যেমন আগ্রহ দেখিয়েছেন করার জন্য সুর উপাদান পারবেন mixins: [createStoreMixin(UserStore)]

function createStoreMixin(...stores) {
  var StoreMixin = {
    getInitialState() {
      return this.getStateFromStores(this.props);
    },

    componentDidMount() {
      stores.forEach(store =>
        store.addChangeListener(this.handleStoresChanged)
      );

      this.setState(this.getStateFromStores(this.props));
    },

    componentWillUnmount() {
      stores.forEach(store =>
        store.removeChangeListener(this.handleStoresChanged)
      );
    },

    handleStoresChanged() {
      if (this.isMounted()) {
        this.setState(this.getStateFromStores(this.props));
      }
    }
  };

  return StoreMixin;
}

1
আপনি স্ট্যাম্পসি লিখেছেন এই সত্যটি প্রদান করে আপনি যদি পুরো ক্লায়েন্টের পাশের অ্যাপ্লিকেশনটি আবার লিখতে চান, আপনি কি এই উদাহরণ অ্যাপ্লিকেশনটি তৈরির জন্য ব্যবহার করেছেন FLUX এবং একই পন্থাটি ব্যবহার করবেন?
eAbi

2
ইএবি: ফ্ল্যাক্সে স্ট্যাম্পসি পুনর্লিখন করার সময় আমরা বর্তমানে এই পদ্ধতিটি ব্যবহার করছি (এটি পরের মাসে প্রকাশের আশায়)। এটি আদর্শ নয় তবে এটি আমাদের পক্ষে ভাল কাজ করে। কখন / যদি আমরা সেই জিনিসগুলি করার আরও ভাল উপায়গুলি খুঁজে পাই, আমরা সেগুলি ভাগ করব।
ড্যান আব্রামভ

1
eAbi: তবে আমরা আর সাধারণকরণ ব্যবহার করি না কারণ একটি লোক, আমাদের টিম আমাদের সমস্ত API গুলি পুনরায় লেখায় স্বাভাবিক প্রতিক্রিয়া ফিরিয়ে দেয়। যদিও এটি করার আগে এটি কার্যকর ছিল।
ড্যান আব্রামভ

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

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

27

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

Actions <-- Store { <-- Another Store } <-- Components

এখানে প্রতিটি তীর মডেল করে যে কীভাবে ডেটা প্রবাহ শোনা যায়, যার পরিবর্তে অর্থ বিপরীত দিকে প্রবাহিত হয়। ডেটা প্রবাহের আসল চিত্র হ'ল:

Actions --> Stores --> Components
   ^          |            |
   +----------+------------+

আপনার ব্যবহারের ক্ষেত্রে, যদি আমি সঠিকভাবে বুঝতে পারি তবে আমাদের openUserProfileএমন একটি ক্রিয়া দরকার যা ব্যবহারকারী প্রোফাইল পৃষ্ঠা লোডিং এবং স্যুইচিং শুরু করে এবং কিছু পোস্ট লোডিং ক্রিয়া যা ব্যবহারকারী প্রোফাইল পৃষ্ঠাটি খোলার সময় এবং অসীম স্ক্রোল ইভেন্টের সময় পোস্টগুলি লোড করবে will সুতরাং আমি কল্পনা করতে পারি যে আমাদের অ্যাপ্লিকেশনটিতে নিম্নলিখিত ডেটা স্টোর রয়েছে:

  • একটি পৃষ্ঠার ডেটা স্টোর যা স্যুইচিং পৃষ্ঠাগুলি পরিচালনা করে
  • একটি ব্যবহারকারী প্রোফাইল ডেটা স্টোর যা পৃষ্ঠাটি খুললে ব্যবহারকারী প্রোফাইল লোড করে
  • একটি পোস্টের তালিকা ডেটা স্টোর যা দৃশ্যমান পোস্টগুলি লোড করে এবং পরিচালনা করে

রিফ্লাক্স এ আপনি এটি সেট আপ করতে চাই:

ক্রিয়াকলাপ

// Set up the two actions we need for this use case.
var Actions = Reflux.createActions(['openUserProfile', 'loadUserProfile', 'loadInitialPosts', 'loadMorePosts']);

পৃষ্ঠার দোকান

var currentPageStore = Reflux.createStore({
    init: function() {
        this.listenTo(openUserProfile, this.openUserProfileCallback);
    },
    // We are assuming that the action is invoked with a profileid
    openUserProfileCallback: function(userProfileId) {
        // Trigger to the page handling component to open the user profile
        this.trigger('user profile');

        // Invoke the following action with the loaded the user profile
        Actions.loadUserProfile(userProfileId);
    }
});

ব্যবহারকারীর প্রোফাইল স্টোর

var currentUserProfileStore = Reflux.createStore({
    init: function() {
        this.listenTo(Actions.loadUserProfile, this.switchToUser);
    },
    switchToUser: function(userProfileId) {
        // Do some ajaxy stuff then with the loaded user profile
        // trigger the stores internal change event with it
        this.trigger(userProfile);
    }
});

পোস্ট স্টোর

var currentPostsStore = Reflux.createStore({
    init: function() {
        // for initial posts loading by listening to when the 
        // user profile store changes
        this.listenTo(currentUserProfileStore, this.loadInitialPostsFor);
        // for infinite posts loading
        this.listenTo(Actions.loadMorePosts, this.loadMorePosts);
    },
    loadInitialPostsFor: function(userProfile) {
        this.currentUserProfile = userProfile;

        // Do some ajax stuff here to fetch the initial posts then send
        // them through the change event
        this.trigger(postData, 'initial');
    },
    loadMorePosts: function() {
        // Do some ajaxy stuff to fetch more posts then send them through
        // the change event
        this.trigger(postData, 'more');
    }
});

উপাদানগুলো

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

  • ব্যবহারকারী প্রোফাইলগুলি খুলবে এমন বোতামগুলির Action.openUserProfileক্লিক ইভেন্টের সময় সঠিক আইডির সাথে অনুরোধ করা উচিত।
  • পৃষ্ঠার উপাদানটি শোনা উচিত currentPageStoreযাতে কোন পৃষ্ঠায় স্যুইচ করতে হয় তা তা জানে।
  • ব্যবহারকারীর প্রোফাইল পৃষ্ঠার উপাদানটি শুনতে হবে currentUserProfileStoreতাই এটি ব্যবহারকারী প্রোফাইল ডেটাটি প্রদর্শন করতে পারে knows
  • currentPostsStoreলোড হওয়া পোস্টগুলি পাওয়ার জন্য পোস্টগুলির তালিকাটি শুনতে হবে
  • অসীম স্ক্রোল ইভেন্টটির কল করতে হবে Action.loadMorePosts

এবং এটি বেশ কিছুটা হওয়া উচিত।


লেখার আপ জন্য ধন্যবাদ!
ড্যান আব্রামভ

2
পার্টিতে কিছুটা দেরি হতে পারে, তবে কেন স্টোর থেকে সরাসরি আপনাকে এপিআই কল করা এড়াতে হবে তা ব্যাখ্যা করার জন্য একটি দুর্দান্ত নিবন্ধ । আমি এখনও সেরা অনুশীলনগুলি কী তা নির্ণয় করছি তবে আমি ভেবেছিলাম এটি এটি অন্য কোনও হোঁচট খাতে সহায়তা করে। স্টোরগুলি সম্পর্কে বিভিন্ন দিকে প্রচুর ভাসমান রয়েছে।
থিজস কোয়ারসেলম্যান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.