SolidJS 2.0 একটি নেটিভ async-data মডেল নিয়ে এসেছে যা একটি কম্পোনেন্টকে একটি promise-কে অন্য যেকোনো reactive value-এর মতো ব্যবহার করতে দেয়, এবং এটি React ডেভেলপাররা Suspense এবং hooks-এর ক্ষেত্রে যে রেন্ডারিংয়ের ধারাবাহিকতা (cascade of re-renders) দেখেন, তা ছাড়াই সম্পন্ন করে। এই পরিবর্তনটি গুরুত্বপূর্ণ কারণ এটি ডেটা রিফ্রেশ হওয়ার সময় UI স্ক্রিনে বজায় রাখে, অপ্রয়োজনীয় কোড (boilerplate) কমায় এবং React টিমগুলোর জন্য তাদের ডেটা-ফেচিং কোড Solid-এ স্থানান্তরের একটি সুনির্দিষ্ট পথ তৈরি করে।

কেন Solid-এর async মডেলটি আলাদা মনে হয়

React-এ, যে কম্পোনেন্টের ডেটা প্রয়োজন সেটি সাধারণত একটি hook (প্রায়শই একটি কাস্টম hook) কল করে যা একটি promise-এর মতো অবজেক্ট রিটার্ন করে, তারপর promiseটি resolve হওয়ার সময় একটি fallback দেখানোর জন্য UI-কে <Suspense> দিয়ে মুড়িয়ে (wrap) দেয়। প্রতিবার যখন promiseটি settle হয়, React একটি re-render শিডিউল করে; যদি একই কম্পোনেন্ট পরে পুনরায় ডেটা ফেচ (refetch) করে, তবে ইতিমধ্যে দৃশ্যমান কন্টেন্টের ওপর fallback-টি হঠাৎ করে ভেসে উঠতে পারে।

Solid এই নিয়মটি বদলে দিয়েছে। একটি promise হলো কেবল একটি value যা reactive graph পর্যবেক্ষণ করে। যখন কোনো computation সেই value-টি পড়ে, graph-টি সেই রিড (read) প্রক্রিয়াটি ততক্ষণ স্থগিত রাখে যতক্ষণ না promiseটি resolve হয়, কিন্তু বাকি UI রেন্ডার অবস্থায় থাকে। প্রথমবার যখন একটি কম্পোনেন্ট mount হয়, তখন একটি <Loading> boundary একটি fallback দেখাতে পারে; এরপর, নতুন ডেটা না আসা পর্যন্ত একটি refetch বিদ্যমান DOM-কে অপরিবর্তিত রাখে। কম্পোনেন্টের ভেতরে কোনো স্পষ্ট “await” নেই, কোনো createResource নেই, এমনকি কোনো ম্যানুয়াল state toggle-ও নেই।

মূল primitives

  • <Loading> boundary – এটি React-এর <Suspense>-এর বিকল্প। এটি কেবল প্রাথমিক লোড হওয়ার সময় একটি fallback দেখায়। প্রথমবার paint হওয়ার পর, একটি pending read UI-কে প্রতিস্থাপন করে না; নতুন value resolve না হওয়া পর্যন্ত পুরনো কন্টেন্টটি থেকে যায়। নির্দিষ্ট কোনো refetch-এর সময় স্পিনার (spinner) দেখাতে একটি on prop ব্যবহার করুন।
  • <Reveal> component – একাধিক <Loading> boundary একসাথে কীভাবে প্রদর্শিত হবে তা নিয়ন্ত্রণ করে। আপনি বেছে নিতে পারেন:
    • Sequential: DOM অর্ডার অনুযায়ী boundary-গুলো একে একে প্রদর্শিত হয়।
    • Together: যখন সব ডেটা প্রস্তুত হয়, তখন সবগুলো একসাথে প্রদর্শিত হয়।
    • Natural: প্রতিটি boundary তার নিজস্ব ডেটা পাওয়ার সাথে সাথেই প্রদর্শিত হয়।
  • isPending signal – একটি নির্দিষ্ট read চলাকালীন এটি true রিটার্ন করে। মূল কন্টেন্ট দৃশ্যমান থাকা অবস্থায় একটি পাতলা লোডিং বার বা সূক্ষ্ম অ্যানিমেশন দেখানোর জন্য এটি ব্যবহার করুন, যা আপনাকে বিনামূল্যে “stale-while-revalidate” সুবিধা প্রদান করে।
  • action generator – এটি React-এর mutable-state আপডেটগুলোর বিকল্প। একটি action(function*…) আশাবাদীভাবে (optimistically) UI আপডেট করতে পারে, সার্ভার রেসপন্সের জন্য yield করতে পারে এবং promiseটি resolve হলে ফলাফলটি reconcile করতে পারে। এতে UI তাৎক্ষণিক মনে হয় এবং reconciliation ধাপটি primitives-এর মধ্যেই বিল্ট-ইন থাকে।

কীভাবে এই অংশগুলো React কনসেপ্টের সাথে মানানসই

বৈশিষ্ট্য React পদ্ধতি Solid 2.0 পদ্ধতি
Data fetching use() (experimental) অথবা third-party hooks; ফলাফল <Suspense> দিয়ে মোড়ানো থাকে createMemo (বা অনুরূপ) যা একটি promise রিটার্ন করে; সরাসরি JSX-এ পড়া হয়
Loading UI প্রতিবার refetch-এর সময় <Suspense> পুনরায় fallback ট্রিগার করতে পারে কেবল প্রথম লোডের সময় <Loading>; refetch পুরনো UI বজায় রাখে
Refreshing UI আপডেট বিলম্বিত করতে useTransition UI পরিবর্তন না করেই isPending দিয়ে pending read-এর সংকেত দেয়
Mutations useState/useReducer + async calls, যা প্রায়শই কাস্টম action-এর মাধ্যমে মোড়ানো থাকে বিল্ট-ইন optimistic handling সহ action(function*…)

এর ব্যবহারিক ফলাফল হলো, React যে বিষয়গুলোকে আলাদা hook হিসেবে বিবেচনা করে, Solid সেগুলোকে এর মূল reactivity engine-এর মধ্যেই বিল্ট-ইন করে রেখেছে।

ধাপে ধাপে মাইগ্রেশন গাইড

  1. ডেটা সোর্স শনাক্ত করুন – React-এ আপনার সম্ভবত const data = useMyFetch(url) থাকে। Solid-এ এটি একটি memo দিয়ে প্রতিস্থাপন করুন যা promise রিটার্ন করে: const data = createMemo(() => fetch(url).then(r => r.json()))
  2. টপ-লেভেল কম্পোনেন্টটি র‍্যাপ (wrap) করুন – যদি promiseটি resolve হওয়ার আগে কম্পোনেন্টটি রেন্ডার হয়, তবে এটিকে <Loading fallback={<Spinner/>}>…</Loading> দিয়ে ঘিরে রাখুন। fallback-টি শুধুমাত্র প্রথম মাউন্টের (mount) সময় দেখা যাবে।
  3. প্রতিবার রি-ফেচ করার সময় স্পিনার ব্যবহারের পরিবর্তে পরিবর্তন করুন – যেখানে আপনি আগে একটি loading flag টগল করতেন, এখন সেখানে isPending(data) পড়ুন। বিদ্যমান UI স্ক্রিনে থাকা অবস্থায় একটি সূক্ষ্ম ইন্ডিকেটর (indicator) রেন্ডার করতে সেই boolean ব্যবহার করুন।
  4. optimistic updates কনভার্ট করুন – যদি আপনার কাছে একটি async কলের আগে setState(prev => ({...prev, optimisticValue})) থাকতো, তবে সেটিকে এভাবে পুনরায় লিখুন: const update = action(function* (newValue) { state = newValue; const server = yield fetch(...); state = reconcile(server); });। জেনারেটরটি সার্ভার রেসপন্স না করা পর্যন্ত কন্ট্রোল ধরে রাখে, তারপর স্বয়ংক্রিয়ভাবে রিঅ্যাক্টিভ গ্রাফ আপডেট করে।
  5. একাধিক async অংশ হ্যান্ডেল করুন – প্রয়োজন অনুযায়ী <Loading> বাউন্ডারিগুলো নেস্ট (nest) করুন, তারপর তারা একসাথে নাকি একে একে আসবে তা নির্ধারণ করতে একটি <Reveal> র‍্যাপার যোগ করুন। এটি সেই প্যাটার্নগুলোকে প্রতিস্থাপন করে যেখানে React ডেভেলপাররা জটিল state চেক ব্যবহার করে একাধিক <Suspense> কম্পোনেন্ট পর্যায়ক্রমে দেখাতেন।
  6. ফ্লো (flow) পরীক্ষা করুন – যেহেতু Solid promise resolution-এর সময় পুনরায় রেন্ডার (re-render) হয় না, তাই UI আপডেটগুলো আপনার প্রত্যাশা অনুযায়ী হচ্ছে কি না তা যাচাই করে নিন। রিঅ্যাক্টিভ গ্রাফ স্বয়ংক্রিয়ভাবে পরিবর্তনগুলো ছড়িয়ে দেয়; অতিরিক্ত useEffect কলের প্রয়োজন নেই।

যা এখনও পরিবর্তনশীল

Solid 2.0-এর async API বর্তমানে বিটা (beta) পর্যায়ে আছে। স্ট্যাবল রিলিজের আগে <Loading> এবং action-এর মতো নামগুলো পরিবর্তিত হতে পারে এবং ডকুমেন্টেশন এখনও বিবর্তিত হচ্ছে। মূল ধারণাটি—promise-কে রিঅ্যাক্টিভ ভ্যালু হিসেবে বিবেচনা করা—অপরিবর্তিত রয়েছে, তবে লাইব্রেরিটি স্থিতিশীল হওয়ার সাথে সাথে শুরুর দিকের ব্যবহারকারীদের সামান্য ব্রেকিং চেঞ্জ (breaking changes) আশা করা উচিত।

কারা উপকৃত হবেন

  • প্রচুর ডেটা ফেচিং করা React টিম – এক্সটার্নাল স্টেট লাইব্রেরির প্রয়োজনীয়তা হ্রাস এবং বিল্ট-ইন stale-while-revalidate প্যাটার্ন বান্ডেল সাইজ কমাতে পারে এবং কোডবেস সহজ করতে পারে।
  • পারফরম্যান্স-কেন্দ্রিক অ্যাপ – প্রতিবার ফেচ করার সময় সম্পূর্ণ কম্পোনেন্ট রেন্ডার হওয়া এড়িয়ে Solid আরও মসৃণ ভিজ্যুয়াল আপডেট প্রদান করে, বিশেষ করে লো-এন্ড ডিভাইসে।
  • যারা “flash of spinner” নিয়ে বিরক্ত<Loading> বাউন্ডারির “first-load-only” আচরণটি ইতিমধ্যে দৃশ্যমান কন্টেন্টের ওপর স্পিনার ফ্ল্যাশ করার সাধারণ বিরক্তি দূর করে।

সম্ভাব্য অসুবিধাগুলো

  • বিটা স্ট্যাটাস – API স্থিতিশীল না হওয়া পর্যন্ত, দীর্ঘমেয়াদী প্রজেক্টগুলোর পরবর্তীতে মাইগ্রেশন প্রচেষ্টার জন্য বাজেট রাখা প্রয়োজন হতে পারে।

পরবর্তীতে যা খেয়াল রাখতে হবে

<Loading> বা action-এর যেকোনো রিনেমের (renaming) জন্য অফিসিয়াল চেঞ্জলগের (changelog) দিকে নজর রাখুন।

মূল কথা: SolidJS 2.0 আপনাকে promise-কে ফার্স্ট-ক্লাস রিঅ্যাক্টিভ ভ্যালু হিসেবে ব্যবহার করতে দেয়, যা ডেটা রিফ্রেশ হওয়ার সময় UI-কে স্থির রাখে এবং React-স্টাইল হুক-এর একটি সম্পূর্ণ সেটের প্রয়োজনীয়তা দূর করে। যারা রেন্ডার-কেন্দ্রিক মডেল থেকে বেরিয়ে আসতে প্রস্তুত, তাদের জন্য মাইগ্রেশন পথটি স্পষ্ট, পারফরম্যান্সের সুবিধাটি দৃশ্যমান এবং একমাত্র প্রকৃত ঝুঁকি হলো বিটা-পর্যায়ের সাধারণ অনিশ্চয়তা।