म यो लेख लेख्दै छु किनभने मैले मेरो जस्तो देखिने समाधान फेला पारेको छैन, त्यसैले मेरो समाधान अरू कसैको लागि उपयोगी हुन सक्छ।
सामग्री तालिका
कार्यान्वयन
कक्षाहरू लागू गर्नुहोस्
प्रतिक्रिया हुकमा राज्य ढाँचा प्रयोग गर्नुहोस्
पूरा कोड, ताकि तपाईं प्रतिलिपि-टाँस्न सक्नुहुन्छ।
विस्तारित अवस्था मेसिन (त्रुटि अवस्था, प्रतिलिपि-टाँस्ने 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 Hook मा State Pattern प्रयोग गर्नुहोस्
अर्को समस्या: हामी कसरी प्रतिक्रियासँग संयोजनमा कक्षाहरू प्रयोग गर्ने?
अन्य लेखहरूले हालको अवस्थाको नाम भण्डारण गर्न useEffect
र स्ट्रिङ प्रयोग गर्छन्; हामी हाम्रो कार्यान्वयन सफा राख्न चाहन्छौं।
यदि roomClient
setState
प्रकार्यको सन्दर्भ छ भने, यसले state परिमार्जन गर्न सक्छ।
समस्याहरू:
- यदि हामीले क्लाससँग स्टेट इनिसियलाइज गर्यौं भने हामी
setState
पास गर्न सक्दैनौं। - हामी हुकबाट नल फर्काउन चाहँदैनौं।
- हामी हुकबाट केही पनि नफर्काउने नक्कली विधिहरू फिर्ता गर्न चाहँदैनौं।
समाधान, state सुरु हुने बित्तिकै useState
ठीक तल 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
स्थितिमा ट्रान्जिसन गर्न चाहने भएकोले हामीले स्टेट मेसिनलाई विस्तार गर्छौं, र यसले गलत अपरेशन निम्त्याउँछ। यसले हामीलाई 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/[email protected]/umd/react.development.js"></script> <script src="https://cdn.jsdelivr.net/npm/[email protected]/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>
यसले कस्ता समस्याहरू समाधान गर्छ?
- हामी अवस्थित कोड परिमार्जन नगरी राज्य मेसिनलाई मापन गर्न सक्छौं।
- कम बगहरू।
- एकपटक हामीले यो कसरी काम गर्छ भनेर बुझेपछि, अझ बुझ्न सकिने कोड (हामीले गर्नुपर्ने भनेको नयाँ राज्यको लागि नयाँ कक्षा थप्नु हो) ।
- जटिल यदि-अन्य ब्लकहरू, जटिल अवस्था उत्परिवर्तनहरू, र एक स्विच स्टेटमेन्टबाट बच्नुहोस्।
- यदि तपाईं WebSockets प्रयोग गरेर वास्तविक-समय कोठाहरू सिर्जना गर्न चाहनुहुन्छ भने यो राम्रो छ (हामी प्रयोगकर्ता कोठा जडान अवस्था र अन्य प्रकारका अवस्थाहरू निगरानी गर्न सक्छौं)।
यो लेख किन अर्थपूर्ण छ?
जब मैले गुगलमा state design pattern
खोजेँ, यी मेरा पहिलो नतिजाहरू थिए।
३ वटा नतिजाका लिङ्कहरू:
- https://refactoring.guru/design-patterns/state
- https://en.wikipedia.org/wiki/State_pattern
- https://www.geeksforgeeks.org/state-design-pattern/
- https://medium.com/@udaykale/evolving-the-state-design-pattern-e6682a866fdd
react state design pattern
खोजी गर्दा https://refactoring.guru/design-patterns/state मा कार्यान्वयन जस्तो नदेखिने कार्यान्वयनहरू प्राप्त हुन्छन्।
खोजबाट प्राप्त नतिजाहरूको लिङ्कहरू:
- https://medium.com/@yah.emam/state-design-pattern-using-react-hooks-c535e1daa6f1
- https://blog.logrocket.com/modern-guide-react-state-patterns/
- https://github.com/themithy/react-design-patterns/blob/master/doc/state-pattern.md
- https://refine.dev/blog/react-design-patterns/
- https://react.dev/learn/choosing-the-state-structure