paint-brush
জাভাস্ক্রিপ্টে স্টেট ডিজাইন প্যাটার্ন কীভাবে বাস্তবায়ন করবেন এবং এটিকে রিঅ্যাক্ট হুকের সাথে একীভূত করবেনদ্বারা@anonymouswriter_randomhandleasdad123125156135
নতুন ইতিহাস

জাভাস্ক্রিপ্টে স্টেট ডিজাইন প্যাটার্ন কীভাবে বাস্তবায়ন করবেন এবং এটিকে রিঅ্যাক্ট হুকের সাথে একীভূত করবেন

দ্বারা anonymouswriter13m2025/03/22
Read on Terminal Reader

অতিদীর্ঘ; পড়তে

আমি এই প্রবন্ধটি লিখছি কারণ আমি আমার মতো দেখতে কোনও সমাধান খুঁজে পাইনি, তাই আমার সমাধান অন্য কারও জন্য কার্যকর হতে পারে। আমরা রিফ্যাক্টরিং গুরু যেমন সুপারিশ করেন ঠিক তেমনই স্টেট ডিজাইন প্যাটার্নটি বাস্তবায়ন করি। রিঅ্যাক্ট হুকে স্টেট প্যাটার্নটি ব্যবহার করুন।
featured image - জাভাস্ক্রিপ্টে স্টেট ডিজাইন প্যাটার্ন কীভাবে বাস্তবায়ন করবেন এবং এটিকে রিঅ্যাক্ট হুকের সাথে একীভূত করবেন
anonymouswriter HackerNoon profile picture

আমি এই প্রবন্ধটি লিখছি কারণ আমি আমার মতো দেখতে কোনও সমাধান খুঁজে পাইনি, তাই আমার সমাধান অন্য কারো জন্য কার্যকর হতে পারে।

সূচি তালিকা

  • বাস্তবায়ন

    • ক্লাসগুলি বাস্তবায়ন করুন

    • রিঅ্যাক্ট হুকে স্টেট প্যাটার্ন ব্যবহার করুন।


  • সম্পূর্ণ কোড, যাতে আপনি কপি-পেস্ট করতে পারেন।


  • বর্ধিত অবস্থা মেশিন (ত্রুটি অবস্থা, কপি-পেস্টযোগ্য HTML)

    • চিত্র

    • কোড


  • এটি কোন সমস্যার সমাধান করে?

  • এই প্রবন্ধটি কেন যুক্তিসঙ্গত।

বাস্তবায়ন

আমরা রিফ্যাক্টরিং গুরু যেভাবে সুপারিশ করেন ঠিক সেভাবেই স্টেট ডিজাইন প্যাটার্ন বাস্তবায়ন করি: https://refactoring.guru/design-patterns/state

ক্লাসগুলি বাস্তবায়ন করুন

 class RoomState { #roomClient = null; #roomId = null; constructor(roomClient, roomId) { if (roomClient) { this.#roomClient = roomClient; } if (roomId) { this.roomId = roomId; } } set roomClient(roomClient) { if (roomClient) { this.#roomClient = roomClient; } } get roomClient() { return this.#roomClient; } set roomId(roomId) { if (roomId) { this.#roomId = roomId; } } get roomId() { return this.#roomId; } join(roomId) { throw new Error('Abstract method join(roomId).'); } leave() { throw new Error('Abstract method leave().'); } getStatusMessage() { throw new Error('Abstract method getStatusMessage().'); } } // ------------------------------------------------------------------------- class PingRoomState extends RoomState { join(roomId) { this.roomClient.setState(new PongRoomState(this.roomClient, roomId)); } leave() { const message = `Left Ping room ${this.roomId}`; this.roomClient.setState(new LeftRoomState(this.roomClient, message)); } getStatusMessage() { return `In the Ping room ${this.roomId}`; } } // ------------------------------------------------------------------------- class PongRoomState extends RoomState { join(roomId) { this.roomClient.setState(new PingRoomState(this.roomClient, roomId)); } leave() { const message = `Left Pong room ${this.roomId}`; this.roomClient.setState(new LeftRoomState(this.roomClient, message)); } getStatusMessage() { return `In the Pong room ${this.roomId}`; } } // ------------------------------------------------------------------------- class LeftRoomState extends RoomState { #previousRoom = null; constructor(roomClient, previousRoom) { super(roomClient); this.#previousRoom = previousRoom; } join(roomId) { this.roomClient.setState(new PingRoomState(this.roomClient, roomId)); } leave() { throw new Error(`Can't leave, no room assigned`); } getStatusMessage() { return `Not in any room (previously in ${this.#previousRoom})`; } }

এটাই এখন পর্যন্ত আমাদের রাষ্ট্রীয় যন্ত্র।

অবস্থা মেশিন চিত্র


রিঅ্যাক্ট হুকে স্টেট প্যাটার্ন ব্যবহার করুন

পরবর্তী সমস্যা: আমরা কীভাবে ক্লাসগুলিকে react এর সাথে একত্রে ব্যবহার করব?

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

যদি setState ফাংশনের রেফারেন্স থাকে, তাহলে roomClient অবস্থা পরিবর্তন করতে পারে।


সমস্যা:

  • যদি আমরা ক্লাস দিয়ে স্টেটটি ইনিশিয়ালাইজ করি, তাহলে আমরা setState পাস করতে পারব না।
  • আমরা হুক থেকে নাল ফেরত দিতে চাই না।
  • আমরা এমন মক পদ্ধতিগুলি ফেরত দিতে চাই না যা হুক থেকে কিছুই ফেরত দেয় না।


সমাধান, useState ঠিক নীচে, state শুরু হওয়ার সাথে সাথে roomClient প্রদান করুন।

 function useRoomClient() { const [state, setState] = useState(new PingRoomState()); // State contains the class // Initialize once // We can do this thanks to the `set` and `get` methods on // `roomClient` property if (!state.roomClient) { state.roomClient = { setState }; } return state; }

সম্পূর্ণ কোড যাতে আপনি কপি-পেস্ট করতে পারেন

 class RoomState { #roomClient = null; #roomId = null; constructor(roomClient, roomId) { if (roomClient) { this.#roomClient = roomClient; } if (roomId) { this.roomId = roomId; } } set roomClient(roomClient) { if (roomClient) { this.#roomClient = roomClient; } } get roomClient() { return this.#roomClient; } set roomId(roomId) { if (roomId) { this.#roomId = roomId; } } get roomId() { return this.#roomId; } join(roomId) { throw new Error('Abstract method join(roomId).'); } leave() { throw new Error('Abstract method leave().'); } getStatusMessage() { throw new Error('Abstract method getStatusMessage().'); } } // ------------------------------------------------------------------------- class PingRoomState extends RoomState { join(roomId) { this.roomClient.setState(new PongRoomState(this.roomClient, roomId)); } leave() { const message = `Left Ping room ${this.roomId}`; this.roomClient.setState(new LeftRoomState(this.roomClient, message)); } getStatusMessage() { return `In the Ping room ${this.roomId}`; } } // ------------------------------------------------------------------------- class PongRoomState extends RoomState { join(roomId) { this.roomClient.setState(new PingRoomState(this.roomClient, roomId)); } leave() { const message = `Left Pong room ${this.roomId}`; this.roomClient.setState(new LeftRoomState(this.roomClient, message)); } getStatusMessage() { return `In the Pong room ${this.roomId}`; } } // ------------------------------------------------------------------------- class LeftRoomState extends RoomState { #previousRoom = null; constructor(roomClient, previousRoom) { super(roomClient); this.#previousRoom = previousRoom; } join(roomId) { this.roomClient.setState(new PingRoomState(this.roomClient, roomId)); } leave() { throw new Error(`Can't leave, no room assigned`); } getStatusMessage() { return `Not in any room (previously in ${this.#previousRoom})`; } } function useRoomClient() { const [state, setState] = useState(new PingRoomState()); // State contains the class // Initialize once // We can do this thanks to the `set` and `get` methods on // `roomClient` property if (!state.roomClient) { state.roomClient = { setState }; } return state; }

এক্সটেন্ডেড স্টেট মেশিন (ত্রুটি স্টেট, কপি-পেস্টযোগ্য HTML)

আমরা স্টেট মেশিনটি প্রসারিত করি কারণ আমরা যদি ঘর থেকে বেরিয়ে যাওয়ার চেষ্টা করি তবে আমরা Error state এ রূপান্তর করতে চাই, এবং এর ফলে একটি ভুল অপারেশন হয়। এটি আমাদের getStatusMessage কল করে স্ট্যাটাস বার্তা প্রদর্শন করতে দেয়।

চিত্র

ত্রুটি অবস্থা সহ আপডেট করা অবস্থা মেশিন ডায়াগ্রাম



কোড

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="root"></div> <script src="https://cdn.jsdelivr.net/npm/react@18.3.1/umd/react.development.js"></script> <script src="https://cdn.jsdelivr.net/npm/react-dom@18.3.1/umd/react-dom.development.js"></script> <script> class RoomState { #roomClient = null; #roomId = null; constructor(roomClient, roomId) { if (roomClient) { this.#roomClient = roomClient; } if (roomId) { this.roomId = roomId; } } set roomClient(roomClient) { if (roomClient) { this.#roomClient = roomClient; } } get roomClient() { return this.#roomClient; } set roomId(roomId) { if (roomId) { this.#roomId = roomId; } } get roomId() { return this.#roomId; } join(roomId) { throw new Error('Abstract method join(roomId).'); } leave() { throw new Error('Abstract method leave().'); } getStatusMessage() { throw new Error('Abstract method getStatusMessage().'); } } // ------------------------------------------------------------------------- class PingRoomState extends RoomState { join(roomId) { this.roomClient.setState(new PongRoomState(this.roomClient, roomId)); } leave() { const message = `Left Ping room ${this.roomId}`; this.roomClient.setState(new LeftRoomState(this.roomClient, message)); } getStatusMessage() { return `In the Ping room ${this.roomId}`; } } // ------------------------------------------------------------------------- class PongRoomState extends RoomState { join(roomId) { this.roomClient.setState(new PingRoomState(this.roomClient, roomId)); } leave() { const message = `Left Pong room ${this.roomId}`; this.roomClient.setState(new LeftRoomState(this.roomClient, message)); } getStatusMessage() { return `In the Pong room ${this.roomId}`; } } // ------------------------------------------------------------------------- class LeftRoomState extends RoomState { #previousRoom = null; constructor(roomClient, previousRoom) { super(roomClient); this.#previousRoom = previousRoom; } join(roomId) { this.roomClient.setState(new PingRoomState(this.roomClient, roomId)); } leave() { // Extend to shift to error state this.roomClient.setState( new ErrorRoomState( this.roomClient, new Error(`Can't leave, no room assigned`), ), ); } getStatusMessage() { return `Not in any room (previously in ${this.#previousRoom})`; } } // Extend our state machine to hold one more state. class ErrorRoomState extends RoomState { #error = null; constructor(roomClient, error) { super(roomClient); this.#error = error; } join(roomId) { this.roomClient.setState(new PingRoomState(this.roomClient, roomId)); } leave() { // Do nothing... We can't move anywhere. We handled error. } getStatusMessage() { return `An error occurred. ${this.#error.message}`; } } const { useState } = React; function useRoomClient() { const [state, setState] = useState(new PingRoomState()); // State contains the class // Initialize once // We can do this thanks to the `set` and `get` methods on // `roomClient` property if (!state.roomClient) { state.roomClient = { setState }; } return state; } // ---------------------------------------------------------------------- // Usage example // ---------------------------------------------------------------------- const e = React.createElement; function useWithError(obj) {} function App() { const roomClient = useRoomClient(); return e( 'div', null, e('h1', null, 'Change room state'), e('p', null, `Status message: ${roomClient.getStatusMessage()}`), e( 'div', null, e('button', { onClick: () => roomClient.join('a') }, 'Join'), e('button', { onClick: () => roomClient.leave() }, 'Leave'), ), ); } const { createRoot } = ReactDOM; const root = document.getElementById('root'); createRoot(root).render(React.createElement(App)); </script> </body> </html>

এটি কোন সমস্যার সমাধান করে?

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

এই প্রবন্ধটি কেন যুক্তিসঙ্গত?

যখন আমি গুগলে state design pattern অনুসন্ধান করি, তখন এইগুলিই ছিল আমার প্রথম ফলাফল।

৩টি ফলাফলের লিঙ্ক:


react state design pattern অনুসন্ধান করলে এমন বাস্তবায়ন পাওয়া যায় যা https://refactoring.guru/design-patterns/state- এ বাস্তবায়নের মতো দেখায় না।

অনুসন্ধানের ফলাফলের লিঙ্ক: