2016-11-30 26 views
5

में कोई ऑब्जेक्ट अपडेट करना मैं एक कोणीय 2 ऐप के लिए @ ngrx/store का उपयोग कर रहा हूं।ngrx/store

मेरी दुकान में Book ऑब्जेक्ट्स की एक सूची है। मैं उन वस्तुओं में से एक में एक फ़ील्ड अपडेट करना चाहता हूं। मुझे पुस्तक उदाहरण का एक अवलोकन भी होता है जिसे मैं अपडेट करना चाहता हूं (कहें, selectedBook)।

अद्यतन करने के लिए मैं UpdateBookAction के साथ रेड्यूसर को कॉल करने का इरादा रखता हूं, और नई पुस्तक का एक पेलोड। तो मैं selectedBook की सदस्यता ले कर और फिर ऑब्जेक्ट.साइन() को कॉल करके मौजूदा बुक ऑब्जेक्ट की गहरी प्रतिलिपि बना देता हूं।

लेकिन जब मैं प्रतिलिपि के किसी एक फ़ील्ड में लिखने का प्रयास करता हूं तो मुझे निम्न त्रुटि मिलती है। (यह वही त्रुटि अगर मैं दुकान में बुक वस्तु को सीधे लिखने की कोशिश करने के लिए थे मैं होता है।)

त्रुटि

Cannot assign to read only property 'name' of object '#<Object>' at ViewWrappedError.BaseError [as constructor] 

कोड

ngOnInit() { 
    this.book$ = this.store.let(fromRoot.getSelectedBook); 
    //... 
} 

someFunction() { 
    //... 
    this.book$.subscribe(book => { 

     let updatedBook = Object.assign({}, book); 
     updatedBook.name = 'something else';   // <--- THIS IS WHAT THROWS 

     let action = new BookUpdateAction(updatedBook); 
     this.store.dispatch(action); 

    } 
} 

टिप्पणियों के बाद स्पष्टीकरण

मैं इस धारणा के तहत था कि मुझे एक पेलोड के साथ कार्रवाई हो सकती है जो स्टोर की पूरी स्थिति नहीं थी। (वास्तव में यह आवश्यक लगता है, नहीं?) मुझे विश्वास है कि यह दस्तावेज दिया गया है।

Action = UPDATE, payload = {'id': 1234, 'name': 'something new'} 

के रूप में उल्लेख किया है, मैं इस तरह है कि कॉल करने पर इरादा:

कार्रवाई मैं लेने के लिए देख रहा हूँ कुछ इस तरह है

this.store.dispatch(action); 
मुमकिन है हुड के नीचे

, ngrx है (अपरिवर्तनीय) वर्तमान स्थिति के साथ reducer करने के लिए मेरी कार्रवाई गुजर रहा है।

तो वहां से, सब कुछ ठीक काम करना चाहिए। रेड्यूसर के अंदर मेरा तर्क मौजूदा स्थिति को विचलित नहीं करता है, यह बस मौजूदा स्थिति में से एक नया बनाता है और मैंने जो पेलोड पास किया है, वह

असली सवाल यह है कि मैं उचित रूप से नया कैसे बना सकता हूं " objectToUpdate "जैसे कि मैं इसे पेलोड के रूप में पास कर सकता हूं।

this.book$.subscribe(book => { 

    let updatedBook = new Book(); 
    updatedBook.id = book.id; 
    //set all other fields manually... 
    updatedBook.name = 'something else'; 

    let action = new BookUpdateAction(updatedBook); 
    this.store.dispatch(action); 

} 

लेकिन हम सिर्फ दो क्षेत्रों यहाँ बात नहीं कर रहे ... अगर मेरी किताब कई क्षेत्रों है क्या:

मैं कुछ इस तरह कर सकता है? क्या मुझे एक फ़ील्ड को अपडेट करने के लिए हर बार एक नई पुस्तक खरोंच से मैन्युअल रूप से निर्माण करना है?

मेरा समाधान Object.assign({}, book) (और पुराने को म्यूटेट नहीं कर रहा है) का उपयोग करके एक गहरी प्रतिलिपि करना था और बाद में उस क्षेत्र को अपडेट करना जो मैं स्पर्श करना चाहता था।

+0

क्या आप पुस्तक ऑब्जेक्ट की परिभाषा पोस्ट कर सकते हैं? ऐसा लगता है कि यह केवल एक लिखने की संपत्ति के साथ एक मुद्दा हो सकता है। –

+0

हां, पुस्तक परिभाषा देखना उपयोगी होगा। क्या आपको एक ही कॉल में ऐसा करने में एक ही समस्या है? जैसे 'ऑब्जेक्ट.साइन ({}, पुस्तक, {नाम:' कुछ और '})'? – rob3c

उत्तर

5

एनजीआरएक्स स्टोर का विचार सत्य का एक और एकमात्र स्थान होना है, जिसका अर्थ है कि सभी वस्तुएं अपरिवर्तनीय हैं, और कुछ भी बदलने का एकमात्र तरीका पूरी तरह से सबकुछ बनाना है।इसके अलावा, आप शायद ngrx फ्रीज (https://github.com/codewareio/ngrx-store-freeze) का उपयोग कर रहे हैं जिसका अर्थ है कि सभी ऑब्जेक्ट केवल पढ़ने के लिए बनाए जाएंगे ताकि आप किसी भी को बदलने में सक्षम न हों (यदि आप पूरी तरह से रेडक्स पैटर्न का पालन करना चाहते हैं तो यह विकास के लिए अच्छा है)। यदि आप उस हिस्से को हटाते हैं जहां स्टोर ऑब्जेक्ट को फ्रीज करता है, तो आप इसे बदल पाएंगे, लेकिन यह सबसे अच्छा अभ्यास नहीं है।

मैं आपको सुझाव दूंगा कि आप निम्नलिखित हैं: डेटा को (अपने मामले की पुस्तकों में) को एक गूंगा घटक में रखने के लिए एसिंक पाइप के साथ देखे गए एनजीआरएक्स का उपयोग करें जो केवल कुछ इनपुट इनपुट और आउटपुट प्राप्त कर सकता है। गूंगा घटक के अंदर, आप उस वस्तु को "प्रतिलिपि बनाकर" उस वस्तु को "संपादित" कर सकते हैं, और आपके द्वारा किए जाने के बाद, आप स्मार्ट घटक में किए गए परिवर्तनों को वापस कर सकते हैं जो स्टोर की सदस्यता लेते हैं और इसे राज्य को बदलने की अनुमति देते हैं दुकान के माध्यम से (प्रतिबद्ध)। इस तरह सबसे अच्छा है क्योंकि पूरे राज्य को वास्तव में छोटे बदलाव के लिए बदलना बहुत आम नहीं है (जैसे दो प्रकार बाध्यकारी, जब उपयोगकर्ता प्रकार ..)।

आप redux पैटर्न का पालन, की तुलना में आप इतिहास को जोड़ने के लिए, जिसका अर्थ है की दुकान पिछले एक्स राज्य मनोरंजन की प्रतियां रखना होगा सक्षम हो जाएगा, तो आप कार्यक्षमता, डिबग करने के लिए आसान, समय आदि

पूर्ववत कर सकते हैं, तो

आपकी समस्या यह है कि आप पूरी स्थिति को पुनर्निर्माण के बजाय सीधे संपत्ति संपादित कर रहे हैं।

+1

हाय डेन्को, उत्तर देने का समय लेने के लिए धन्यवाद। मैंने उपरोक्त स्पष्टीकरण टिप्पणियां जोड़ दी हैं। मैं राज्य को अपरिवर्तनीय रखने के लक्ष्य से अवगत हूं। मैं राज्य को खुद को बदलने की कोशिश नहीं कर रहा हूं, बस इसकी प्रतिलिपि बनाने की कोशिश कर रहा हूं ताकि मैं इसे पेलोड के रूप में पास करने से पहले कॉपी को ट्विक कर सकूं। मुझे लगता है कि आप ngrx-store-freeze के साथ कुछ पर हैं। मुझे संदेह है कि गहरी प्रति वस्तु की केवल पढ़ने वाली प्रकृति के साथ ला रही है। यह मुझे ngrx-store-freeze को बंद करने के लिए मजबूर करता है, लेकिन मुझे विश्वास है कि मैं "सर्वोत्तम अभ्यास" का पालन करना जारी रखूंगा। यह किसी भी चीज की तुलना में ngrx-store-freeze की कमी हो सकती है। –

4

मुझे ओपी के वास्तविक परिदृश्य के बारे में एक धारणा बनाना होगा।

समस्या

यह एक जमे हुए वस्तु के एक सदस्य को संशोधित करने के संभव नहीं है। इसकी त्रुटि फेंक दी जा रही है।

कारण

ngrx-store-freeze किसी भी वस्तु है कि दुकान में प्रवेश करती है फ्रीज करने के एक मेटा-कम करने के रूप में प्रयोग किया जाता है। किसी अन्य स्थान पर, जब किसी ऑब्जेक्ट को बदलने की आवश्यकता होती है, तो एक उथली प्रतिलिपि बनाई जा रही है। Object.assign() गहरी प्रति नहीं करता है। मूल वस्तु से प्राप्त किसी अन्य ऑब्जेक्ट का सदस्य संशोधित किया जा रहा है। यह द्वितीयक वस्तु भी जमे हुए है, इसे डुप्लिकेट नहीं किया गया है

समाधान

lodash से cloneDeep() की तरह एक गहरी प्रतिलिपि का उपयोग करें। या उचित कार्रवाई के साथ संपत्तियों का एक बैग बदला जा सकता है। Reducer पर परिवर्तन की प्रक्रिया करें।

1

जैसा कि पहले ही उल्लेख किया है - कारण आप

हो रही है

वस्तु

का केवल संपत्ति 'नाम' को पढ़ने के लिए आवंटित नहीं किया जा सकता क्योंकि 'ngrx-दुकान-फ्रीज' राज्य से रोकती जमा है इसे बदलना

आपकी अपेक्षा के

Object.assign एक नई वस्तु प्रदान करेगा, लेकिन यह प्रत्येक प्रॉपर्टी की अपनी परिभाषा के साथ-साथ राज्य की प्रतिलिपि बनाएगा - जैसे 'लिखने योग्य' परिभाषा के रूप में (जो 'ngrx-दुकान-फ्रीज' संभावना सेट झूठी करने के लिए)।

एक अलग दृष्टिकोण JSON.parse (JSON.stringify (yourObject)) के रूप में सबसे तेजी से साथ in this answer वर्णन किया गया है और बताते हैं कि कैसे क्लोनिंग वस्तुओं, लेकिन इस दृष्टिकोण खामियां है अगर तुम तिथि या अपने राज्य में तरीकों आदि 'रहते हैं।

लॉनाश के 'क्लोनडिप' का उपयोग करके राज्य को गहरे क्लोनिंग के लिए शायद आपकी सबसे अच्छी शर्त है।