2017-04-09 12 views
10

मैं त्रुटि हो रही हैचेतावनी: setState (...):/redux के साथ एक मौजूदा राज्य संक्रमण के दौरान अद्यतन नहीं कर सकते अपरिवर्तनीय

चेतावनी: setState (...): किसी मौजूदा राज्य संक्रमण के दौरान अद्यतन नहीं कर सकते (जैसे render या किसी अन्य घटक के कन्स्ट्रक्टर के भीतर)। रेंडर विधियों को प्रोप और राज्य का शुद्ध कार्य होना चाहिए; कन्स्ट्रक्टर दुष्प्रभाव एक विरोधी पैटर्न हैं, लेकिन componentWillMount पर ले जाया जा सकता है।

मैंने पाया कारण

const mapStateToProps = (state) => { 
    return { 
    notifications: state.get("notifications").get("notifications").toJS() 
    } 
} 

होने के लिए मैं वहां सूचनाएं यह काम करता है वापसी नहीं है, तो। लेकिन वह क्यों है?

import {connect} from "react-redux" 
import {removeNotification, deactivateNotification} from "./actions" 
import Notifications from "./Notifications.jsx" 

const mapStateToProps = (state) => { 
    return { 
    notifications: state.get("notifications").get("notifications").toJS() 
    } 
} 

const mapDispatchToProps = (dispatch) => { 
    return { 
    closeNotification: (notification) => { 
     dispatch(deactivateNotification(notification.id)) 
     setTimeout(() => dispatch(removeNotification(notification.id)), 2000) 
    } 
    } 
} 

const NotificationsBotBot = connect(mapStateToProps, mapDispatchToProps)(Notifications) 
export default NotificationsBotBot 

import React from "react" 

class Notifications extends React.Component { 
    render() { 
    return (
     <div></div> 
    ) 
    } 
} 

export default Notifications 

अद्यतन

आगे डिबगिंग पर मैंने पाया कि, ऊपर सूचनाएं रहने सब के बाद, मैं हो सकता है मूल कारण नहीं हो सकता है, लेकिन मैं dispatch(push("/domains")) मेरी रीडायरेक्ट निकाल की जरूरत है।

export function doLogin (username, password) { 
    return function (dispatch) { 
    dispatch(loginRequest()) 
    console.log("Simulated login with", username, password) 
    setTimeout(() => { 
     dispatch(loginSuccess(`PLACEHOLDER_TOKEN${Date.now()}`)) 
     dispatch(addNotification({ 
     children: "Successfully logged in", 
     type: "accept", 
     timeout: 2000, 
     action: "Ok" 
     })) 
     dispatch(push("/domains")) 
    }, 1000) 
    } 
} 

मुझे लगता है कि प्रेषण चेतावनी का कारण बनता है, लेकिन क्यों:

यह मैं कैसे के लिए लॉग इन है?

import {connect} from "react-redux" 
import DomainsIndex from "./DomainsIndex.jsx" 

export default connect()(DomainsIndex) 

DomainsIndex

export default class DomainsIndex extends React.Component { 
    render() { 
    return (
     <div> 
     <h1>Domains</h1> 
     </div> 
    ) 
    } 
} 

अद्यतन 2

मेरे App.jsx: मेरे डोमेन पेज ज्यादा वर्तमान में कुछ भी नहीं है। <Notifications /> कौन-सी सूचनाएं

<Provider store={store}> 
    <ConnectedRouter history={history}> 
     <Layout> 
     <Panel> 
      <Switch> 
      <Route path="/auth" /> 
      <Route component={TopBar} /> 
      </Switch> 

      <Switch> 
      <Route exact path="/" component={Index} /> 
      <Route path="/auth/login" component={LoginBotBot} /> 
      <AuthenticatedRoute exact path="/domains" component={DomainsPage} /> 
      <AuthenticatedRoute exact path="/domain/:id" component={DomainPage} /> 
      <Route component={Http404} /> 
      </Switch> 
      <Notifications /> 
     </Panel> 
     </Layout> 
    </ConnectedRouter> 
    </Provider> 
+3

आप हमें खेलने के लिए के लिए एक रेपो के लिए कोड को अपलोड कर सकते हैं त्रुटि redux राज्य में एक अद्यतन ट्रिगर हो सकता है इसके साथ? इस सेटअप के साथ पता लगाना मुश्किल है। –

+0

एक तरफ ध्यान दें, बल्कि .Get() का उपयोग करने से है। मिलता है() आप .getIn ([]) का उपयोग करना चाहिए। –

+1

मेरे अनुभव में यह क्रियाओं की संरचना के बारे में नहीं है, बल्कि उस स्थान के बारे में अधिक है जहां से कार्यवाही शुरू हो जाती है।आम तौर पर आप 'घटकWillMount' या' रेंडर' से 'क्रिया को ट्रिगर करते समय यह त्रुटि देखते हैं। गलती से भी, उदा। जब 'onClick = {action}' के बजाय 'onClick = {action()} 'लिखते हैं। – Sulthan

उत्तर

6

प्रदर्शित करता है आपका dispatch(push('/domains')) अन्य डिस्पैच कि एक जुड़ा घटक (शायद एक है कि सूचनाओं के बारे में परवाह करता है) कि remounted हो जाता है/अनमाउंट किया push प्रभावी होता है के बाद के लिए राज्य की स्थापना की साथ आता है।

एक कामकाज और अवधारणा के सबूत के रूप में, dispatch(push('/domains')) को नेस्टेड शून्य-सेकंड setTimeout के साथ कॉल करने का प्रयास करें। यह push पर अमल करना चाहिए अन्य कार्यों के किसी भी समाप्त होने के बाद (अर्थात उम्मीद है कि एक प्रस्तुत करना):

setTimeout(() => dispatch(push('/domains')), 0) 

अगर वह काम करता है, तो आप अपने घटक संरचना पर पुनर्विचार कर सकते हैं। मुझे लगता है कि Notifications एक ऐसा घटक है जिसे आप एक बार माउंट करना चाहते हैं और इसे एप्लिकेशन के जीवनकाल के लिए वहां रखना चाहते हैं। घटक पेड़ में इसे उच्च रखकर इसे PureComponent (यहां docs) बनाकर इसे पुन: प्राप्त करने का प्रयास करें। साथ ही, यदि आपके एप्लिकेशन की जटिलता बढ़ जाती है, तो आपको redux-saga जैसे एसिंक कार्यक्षमता को संभालने के लिए लाइब्रेरी का उपयोग करने पर विचार करना चाहिए।

हालांकि इस चेतावनी आम तौर पर एक गलत कार्रवाई कॉल के कारण प्रतीत होता है (उदाहरण के लिए प्रस्तुत करना पर एक कार्रवाई बुला: onClick={action()} बजाय एक लैम्ब्डा के रूप में पारित करने की: onClick={() => action()}), यदि आपका घटकों आप की तरह लग रहे उल्लेख किया है (सिर्फ एक div प्रतिपादन) , तो यह समस्या का कारण नहीं है।

+0

मैं 0 देरी और 1s देरी से setTimeout की कोशिश की, दोनों अब भी वही त्रुटि का परिणाम है। मैं अपने सवाल में अधिक विवरण जोड़ने के लिए –

+0

मैं कहना चाहता हूँ हमें एक रेपो का एक लिंक प्रदान की कोशिश करेंगे। अन्यथा यह पिन करना असंभव है –

0

वहाँ एक निश्चित जवाब देने के लिए पर्याप्त जानकारी नहीं है। लेकिन क्या निश्चित है कि यह चेतावनी है जब आप render विधि के अंदर setState की कोशिश करता है उठाया जाता है।

अक्सर ऐसा होता है जब आप अपने हैंडलर कार्यों बुला रहे हैं के बजाय बच्चे Component को रंगमंच की सामग्री के रूप में उन्हें गुजर। जैसे यह here या here हुआ।

तो मेरी सलाह दोहरी जांच जो Components अपने /domains मार्ग पर प्रदान किया जा रहा है और आप उन्हें कैसे करने के लिए और अपने बच्चों के लिए संचालकों onChange, onClick, आदि से गुजर रहे हैं के लिए है।

4

मैंने पहले भी इस मुद्दे था, और redux-batched-actions का उपयोग कर इसे हल करने में कामयाब रहे।

यह आपके जैसे उपयोग-मामलों के लिए बहुत उपयोगी है जब आप एक साथ गुणक क्रियाएं भेजते हैं और आप इस बारे में अनिश्चित हैं कि अपडेट ट्रिगर हो जाएंगे, इसके साथ ही, कई कार्रवाइयों के लिए केवल एक ही प्रेषण होगा। आपके मामले में ऐसा लगता है कि बाद में addNotification ठीक है, लेकिन तीसरे एक बहुत अधिक है क्योंकि यह इतिहास एपीआई के साथ सूचना का आदान प्रदान है, हो सकता है।

import { batchActions } from 'redux-batched-actions' 

export function doLogin (username, password) { 
    return function (dispatch) { 

    dispatch(loginRequest()) 
    console.log("Simulated login with", username, password) 

    setTimeout(() => { 

     dispatch(batchActions([ 
     loginSuccess(`PLACEHOLDER_TOKEN${Date.now()}`), 
     addNotification({ 
      children: "Successfully logged in", 
      type: "accept", 
      timeout: 2000, 
      action: "Ok" 
     }), 
     push("/domains") 
     ])) 

    }, 1000) 
    } 
} 

नोट आप करना होगा कि अपने स्टोर में पैकेज और enableBatching अपने कम करने डाउनलोड करने के लिए:

मैं की तरह कुछ करने के लिए (अपने setTimeout संभालने निश्चित रूप से एक API कॉल से बदल दिया जाएगा) की कोशिश करेगा सृष्टि।

1

यह कारण हो रहा है कि आप doLogin पर कॉल कर रहे हैं, अगर आप इसे constructor के भीतर से कॉल कर रहे हैं। यदि ऐसा है तो इसे componentWillMount पर ले जाने का प्रयास करें, हालांकि आपको इस विधि को बटन से कॉल करना चाहिए या लॉगिन फॉर्म में हिट दर्ज करना चाहिए।

यह तो इस समस्या के मूल आप doLogin में प्रत्येक पंक्ति को पता है टिप्पणी की मन वास्तव में कौन-लाइन राज्य समस्या दे रही है, मेरा अनुमान होगा नहीं है constructor should not mutate में प्रलेखित किया गया है या तो push या addNotification

0

एक घटक प्रतिक्रिया जब आप setState({...}) फोन में, यह घटक का कारण बनता है फिर से प्रस्तुत करना है और सभी के जीवन चक्र के तरीकों जो घटक की फिर से प्रतिपादन और render विधि में शामिल हैं कॉल करने के लिए उनमें से एक

है जब render में अगर आप setState({...}) पर कॉल करें, यह फिर से प्रस्तुत करने और प्रस्तुत करने का कारण बन जाएगा आर को बार-बार बुलाया जाएगा, इसलिए यह जावास्क्रिप्ट के अंदर एक अनंत लूप ट्रिगर करेगा जिससे अंततः ऐप

इसलिए न केवल render में बल्कि किसी भी जीवन-चक्र विधि में जो पुन: प्रस्तुत करने की प्रक्रिया का हिस्सा है setState({...}) विधि को नहीं कहा जाना चाहिए।

आपके मामले में कोड है, जबकि अभी भी कोड प्रतिपादन है और इसलिए यह फिर से प्रस्तुत करना और शो के लिए प्रतिक्रिया का कारण बनता है

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