2015-10-23 7 views
17

एक छोटा सा ऐप्लिकेशन में मैं इमारत का उपयोग करता है अभिकर्मक और फिर से फ्रेम मैं प्रेषण करने के लिए जो पेज एप्लिकेशन राज्य में एक मूल्य के आधार पर दिखाया जाना चाहिए बहु तरीकों का उपयोग कर रहा हूँ कर रहा हूँ:रीगेंट/री-फ्रेम के लिए फ़ंक्शन के रूप में बहु-विधियां क्यों काम नहीं कर रही हैं?

(defmulti pages :name) 

(defn main-panel [] 
    (let [current-route (re-frame/subscribe [:current-route])] 
    (fn [] 
     ;... 
     (pages @current-route)))) 

और फिर मैं जैसे तरीकों:

(defmethod layout/pages :register [_] [register-page]) 

जहां register-page समारोह वास्तविक दृश्य उत्पन्न होगा:

(defn register-page [] 
    (let [registration-form (re-frame/subscribe [:registration-form])] 
    (fn [] 
     [:div 
     [:h1 "Register"] 
     ;... 
     ]))) 

मैंकी कोशिश की, जैसा कि:

(defmethod layout/pages :register [_] 
    (let [registration-form (re-frame/subscribe [:registration-form])] 
    (fn [] 
     [:div 
     [:h1 "Register"] 
     ;... 
     ]))) 

और इससे कोई पृष्ठ कभी भी प्रस्तुत नहीं किया गया। अपने मुख्य पैनल में मैं changed the call to pages to square brackets ताकि अभिकर्मक दृश्यता इसे में होगा:

(defn main-panel [] 
    (let [current-route (re-frame/subscribe [:current-route])] 
    (fn [] 
     ;... 
     [pages @current-route]))) 

और उस वजह से पहले का दौरा किया पेज काम करने के लिए, लेकिन उसके बाद, लिंक पर क्लिक करने (जो वर्तमान मार्ग बदलने के लिए कारण बनता है) नहीं है प्रभाव।

व्यक्तिगत विधियों को परिभाषित करने वाले सभी नामस्थानों को पहले लोड किया गया फ़ाइल में आवश्यक है, जिसमें init फ़ंक्शन शामिल है, और तथ्य यह है कि मैं कोई भी पृष्ठ चुन सकता हूं और यह प्रदर्शित करता है कि कोड लोड हो रहा है (फिर, स्विचिंग के लिए एक और पेज काम नहीं करता है):

(defn about-page [] 
    (fn [] 
    [:div "This is the About Page."])) 

(defmethod layout/pages :about [_] 
    [about-page]) 

(defmethod layout/pages :about2 [_] 
    (fn [] 
    [:div "This is the About 2 Page."])) 
:

https://github.com/carouselapps/ninjatools/blob/master/src/cljs/ninjatools/core.cljs#L8-L12

के प्रयास में डिबग करने के लिए क्या हो रहा है, मैं दो मार्गों, :about और :about2, एक समारोह के रूप में एक और एक विधि के रूप एक परिभाषित

और pages पर कॉल करने के परिणाम को लेआउट प्रिंट किया (पाठ्यक्रम के वर्ग ब्रैकेट के बजाय स्पष्ट कॉल का उपयोग करना था)। लिपटे समारोह, एक है कि काम करता है, रिटर्न:

[#object[ninjatools$pages$about_page "function ninjatools$pages$about_page(){ 
return (function(){ 
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [new cljs.core.Keyword(null,"div","div",1057191632),"This is the About Page."], null); 
}); 
}"]] 

जबकि विधि रिटर्न:

#object[Function "function(){ 
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [new cljs.core.Keyword(null,"div","div",1057191632),"This is the About 2 Page."], null); 
}"] 

मैं विधि बदलते हैं होने के लिए:

(defmethod layout/pages :about2 [_] 
    [(fn [] 
    [:div "This is the About 2 Page."])]) 

है कि, लौट एक वेक्टर में कार्य, फिर, यह काम करना शुरू कर देता है।

(defn about-page [] 
    (fn [] 
    [:div "This is the About Page."])) 

(defmethod layout/pages :about [_] 
    about-page) 

के रूप में अभिकर्मक के वाक्य रचना [function] है लेकिन यह समारोह स्वचालित रूप से फोन करने वाला था भावना का एक सा बनाता है: और अगर मैं लिपटे कार्य करने के लिए रिवर्स परिवर्तन करना है, यह विधि के रूप में एक ही तरीके से विफल शुरू होता है ।

मैं भी में के रूप में ब्राउज़र के लिए @current-route outputting, शुरू कर दिया:

[:main.container 
[alerts/view] 
[pages @current-route] 
[:div (pr-str @current-route)]] 

और मैं सत्यापित @current-route सही ढंग से संशोधित किया जा रहा है और उत्पादन अपडेट किया, बस [pages @current-route] नहीं।

मेरी अनुप्रयोग के लिए पूर्ण स्रोत कोड यहां पाया जा सकता: https://github.com/carouselapps/ninjatools/tree/multi-methods

Update: corrected the arity of the methods following Michał Marczyk's answer.

+0

क्या आपको उन नामस्थानों की आवश्यकता है जहां आप कुछ रूट नेमस्पेस में 'defmethod' का उपयोग करते हैं? क्योंकि यदि आपको उन नामस्थानों की स्पष्ट रूप से आवश्यकता नहीं है, तो आपकी विधियां आसानी से multimethod में नहीं जुड़ती हैं। – skrat

+0

@skrat हां। मैं इस बात को ध्यान में रखकर प्रश्न संपादित करूंगा। – Pablo

+0

इसे डीबग करने के लिए मैं 1 होगा। एक डिफ़ॉल्ट विधि जोड़ें और 2. प्रिंट करें कि multimethod क्या लौट रहा है (शायद शून्य)। – PeakCode

उत्तर

4

मैं सभी विवरण नहीं है, लेकिन जाहिरा तौर पर, जब मैं इस तरह के पृष्ठ प्रतिपादन किया गया था:

[:main.container 
[alerts/view] 
[pages @current-route]] 

अभिकर्मक यह नोटिस करने में असफल रहा कि pages@current-route के मान पर निर्भर था। Chrome React plugin ने मुझे इसे समझने में मदद की। मैंने सदस्यता के बजाय एक ratom का उपयोग करने की कोशिश की और यह ठीक काम करने लग रहा था। शुक्र है, telling Reagent/React the key to an element is easy enough:

[:main.container 
[alerts/view] 
^{:key @current-route} [pages @current-route]] 

यह ठीक काम करता है।

+0

अभिकर्मक/प्रतिक्रिया प्रत्येक बार महत्वपूर्ण परिवर्तनों को पृष्ठ घटक को नष्ट और पुन: बनाएगी। तो यह विधि काम करेगी, लेकिन सिर्फ इस बारे में जागरूक रहें। –

+0

बस स्पष्ट होने के लिए, यह कथन: 'अभिकर्मक यह ध्यान देने में विफल रहा था कि @ वर्तमान-मार्ग' के मान पर निर्भर पृष्ठ गलत हैं। क्या हो रहा है इसके स्पष्टीकरण के लिए मेरे उत्तर पर एक नज़र डालें। –

2

पहले समस्या यह है कि मुझ पर बाहर कूदता है कि अपने तरीके कोई तर्क ले:

(defmethod layout/pages :register [] [register-page]) 
           ^arglist 

यहां आपके पास एक खाली arglist है, लेकिन संभवतः आप इस मल्टीमी विधि को एक या दो तर्कों के साथ कॉल करेंगे (क्योंकि इसका प्रेषण कार्य एक कीवर्ड और कीवर्ड सी है एक या दो तर्कों के साथ बुलाया जा सकता है)।

आप एक ही तर्क के साथ इस multimethod कॉल करने के लिए और बस :register विधि के शरीर के अंदर इसे अनदेखा चाहते हैं,

(defmethod layout/pages :register [_] [register-page]) 
           ^argument to be ignored 

इसके अलावा करने के लिए ऊपर बदलने के लिए, मैं उम्मीद आप शायद चाहता हूँ pages पर कॉल करने के लिए पहले जैसा आपने पहले किया था (यानी, प्रश्न में वर्णित स्क्वायर ब्रैकेट में परिवर्तन को वापस लाएं)।


यह ऐप को ठीक या नहीं कर सकता है - अन्य समस्याएं हो सकती हैं - लेकिन आपको इसे शुरू करना चाहिए। (Multimethod निश्चित रूप से उन खाली arglists के साथ काम करेंगे नहीं अगर आप किसी भी बहस में गुजरती हैं।)

+0

तर्क सूची के बारे में अच्छा बिंदु। मुझे लगता है कि क्लोजरस्क्रिप्ट सिर्फ कार्यों और विधियों की धैर्य की जांच नहीं करता है। मैंने यह परिवर्तन किया है लेकिन ऐप अभी भी वैसे ही व्यवहार करता है: https://github.com/carouselapps/ninjatools/commit/971de441b46e407857625d5c8f0b90fd78a54dd0 – Pablo

11

तो, यह की तरह एक घटक: [pages @some-ratom]
rerender होगा जब pages परिवर्तन या @some-ratom बदल जाता है।

अभिकर्मक के दृष्टिकोण से, pages पिछली बार से नहीं बदला है, यह अभी भी वही बहु-विधि है जो पहले था। लेकिन @some-ratom बदल सकता है, ताकि एक पुनर्विक्रय ट्रिगर कर सके।

लेकिन जब यह पुनर्वितरण होता है तो यह pages के कैश किए गए संस्करण का उपयोग करके किया जाएगा। आखिरकार, यह अभिकर्मक प्रतीत नहीं होता है कि pages बदल गया है। यह अभी भी वही multimethod है जो पहले था। mutlimethod के पहले संस्करण और नहीं नया संस्करण हम इस्तेमाल किया देखने की उम्मीद -

pages का संचित संस्करण, ज़ाहिर है, pages का पहला संस्करण है जो प्रस्तुत किया गया है हो जाएगा।

अभिकर्मक इस कैशिंग को करता है क्योंकि इसे फॉर्म -2 कार्यों को संभालना होगा। इसे लौटा रेंडर फ़ंक्शन रखना होगा।

निष्कर्ष: किसी कैशिंग की, मुल्टीमेथड्स, बहुत अच्छी तरह से काम नहीं करेगा क्योंकि जब तक आप पूरी तरह से घटक को उड़ाने और फिर से शुरू करने के लिए एक रास्ता है, जो है जो वर्तमान में टॉप मतदान दृष्टिकोण मिल नहीं जाता:
^{:key @current-route} [pages @current-route]
बेशक, घटक को उड़ाकर और फिर से शुरू करने के अपने स्वयं के अनचाहे प्रभाव हो सकते हैं (उस घटक में स्थानीय राज्य क्या होता है) के आधार पर।

थोड़ा संबंधित पृष्ठभूमि:
https://github.com/Day8/re-frame/wiki/Creating-Reagent-Components#appendix-a---lifting-the-lid-slightly
https://github.com/Day8/re-frame/wiki/When-do-components-update%3F

0

कैसे के बारे में यदि आप के बजाय एक आवरण pages-component समारोह एक नियमित रूप से समारोह है कि अभिकर्मक द्वारा संचित किया जा सकता है जो की है। यह इस तरह दिखेगा:

(defn pages-component [state] 
    (layout/pages @state)) 
संबंधित मुद्दे

 संबंधित मुद्दे