Ես գրում եմ այս հոդվածը, քանի որ ես չեմ գտել լուծում, որը նման է իմին, ուստի իմ լուծումը կարող է օգտակար լինել մեկ ուրիշի համար: Բովանդակության աղյուսակ Իրականացում Իրականացնել դասերը Օգտագործեք վիճակի օրինակը արձագանքման կեռիկում Ամբողջական կոդը, այնպես որ կարող եք պատճենել-տեղադրել: Ընդլայնված վիճակի մեքենա (Սխալի վիճակ, Պատճենել-Pastable 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})`; } } Սա է առայժմ մեր պետական մեքենան Օգտագործեք State Pattern-ը React Hook-ում Հաջորդ խնդիրը. ինչպե՞ս ենք մենք օգտագործում դասերը react-ի հետ համատեղ: Մյուս հոդվածները օգտագործում են և տող՝ ընթացիկ վիճակի անունը պահելու համար. մենք ցանկանում ենք մաքուր պահել մեր իրականացումը: useEffect ը կարող է փոփոխել վիճակը, եթե այն հղում ունի ֆունկցիային: roomClient setState Խնդիրներ: Մենք չենք կարող փոխանցել ը, եթե մենք նախաստորագրենք վիճակը դասի հետ: setState Մենք չենք ցանկանում վերադարձնել null-ը մանգաղից: Մենք չենք ցանկանում վերադարձնել կեղծ մեթոդներ, որոնք ոչինչ չեն վերադարձնում մանգաղից: Լուծում, տրամադրեք , հենց որ վիճակը սկզբնավորվի, հենց ի տակ: roomClient useState 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/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> Ի՞նչ խնդիրներ է այն լուծում: Մենք կարող ենք մասշտաբավորել պետական մեքենան՝ առանց գոյություն ունեցող կոդը փոփոխելու: Ավելի քիչ սխալներ: Ավելի հասկանալի կոդը, երբ մենք հասկանանք, թե ինչպես է այն աշխատում : (մեզ մնում է նոր դաս ավելացնել նոր վիճակի համար) Խուսափեք բարդ if-else բլոկներից, բարդ վիճակի մուտացիաներից և մեկ անջատիչ հայտարարությունից: Հաճելի է, եթե ցանկանում եք ստեղծել իրական ժամանակի սենյակներ՝ օգտագործելով WebSockets (Մենք կարող ենք վերահսկել օգտատերերի սենյակի կապի վիճակը և այլ տեսակի վիճակները): Ինչու այս հոդվածը իմաստ ունի Երբ Google-ում որոնեցի , սրանք իմ առաջին արդյունքներն էին state design pattern Հղումներ դեպի 3 արդյունքներ. 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