एक प्रतिक्रिया / Redux / टाइपस्क्रिप्ट अधिसूचना संदेश में स्वयं से किसी घटक को अनमाउंट, अनरेंडर या निकालने का तरीका


114

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

class ErrorBoxComponent extends React.Component {

  dismiss() {
    // What should I put here?
  }
  
  render() {
    if (!this.props.error) {
      return null;
    }

    return (
      <div data-alert className="alert-box error-box">
        {this.props.error}
        <a href="#" className="close" onClick={this.dismiss.bind(this)}>&times;</a>
      </div>
    );
  }
}


export default ErrorBoxComponent;

और मैं मूल घटक में इसे इस तरह उपयोग करूंगा:

<ErrorBox error={this.state.error}/>

अनुभाग में मुझे यहां क्या करना चाहिए? , मैंने पहले ही कोशिश की:

ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(this).parentNode); जो कंसोल में एक अच्छी त्रुटि फेंकता है:

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

क्या मुझे त्रुटि बॉक्स में आने वाले प्रॉपर कॉपी करना चाहिए, और इसे केवल आंतरिक रूप से हेरफेर करना चाहिए?


क्या आप Redux का उपयोग कर रहे हैं?
अरनू लाकामबरा

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

मैं वास्तव में दोनों के लिए संभावना की पेशकश करना चाहता हूं। वास्तव में, यह बंद करने योग्य होगा जैसा कि आपने इसे समझाया था, लेकिन मेरा मामला यह है कि "क्या होगा अगर मैं भी इसे अंदर से बंद करने में सक्षम होना चाहता हूं"
सिपाही

जवाबों:


97

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

class Child extends React.Component {
    constructor(){}
    dismiss() {
        this.props.unmountMe();
    } 
    render(){
        // code
    }
}

class Parent ...
    constructor(){
        super(props)
        this.state = {renderChild: true};
        this.handleChildUnmount = this.handleChildUnmount.bind(this);
    }
    handleChildUnmount(){
        this.setState({renderChild: false});
    }
    render(){
        // code
        {this.state.renderChild ? <Child unmountMe={this.handleChildUnmount} /> : null}
    }

}

यह एक बहुत ही सरल उदाहरण है। लेकिन आप माता-पिता को एक कार्रवाई से गुजरने के लिए एक मोटा रास्ता देख सकते हैं

कहा जा रहा है कि आपको स्टोर के माध्यम से जाना चाहिए (रेंडर एक्शन) जब आपके स्टोर को सही डेटा देने की अनुमति मिलती है जब वह रेंडर करने के लिए जाता है

मैंने दो अलग-अलग एप्लिकेशन के लिए त्रुटि / स्थिति संदेश किए हैं, दोनों स्टोर से गुजरे हैं। यह पसंदीदा तरीका है ... यदि आप चाहें तो मैं कुछ कोड पोस्ट कर सकता हूं कि यह कैसे करना है।

संपादित करें: यहां बताया गया है कि मैं कैसे प्रतिक्रिया / रिडक्स / टाइपस्क्रिप्ट का उपयोग करके एक अधिसूचना प्रणाली स्थापित करता हूं

पहले ध्यान देने योग्य बातें। यह टाइपस्क्रिप्ट में है इसलिए आपको प्रकार की घोषणाओं को हटाने की आवश्यकता होगी :)

मैं संचालन के लिए एनपीएम पैकेज लॉश का उपयोग कर रहा हूं, और इनलाइन क्लासनाम असाइनमेंट के लिए क्लासनाम (सीएक्स उर्फ)।

इस सेटअप की सुंदरता मैं प्रत्येक अधिसूचना के लिए एक अद्वितीय पहचानकर्ता का उपयोग करता हूं जब कार्रवाई इसे बनाता है। (उदा। Inform_id)। यह यूनिक आईडी एक है Symbol()। इस तरह यदि आप किसी भी समय किसी भी अधिसूचना को हटाना चाहते हैं, क्योंकि आप जानते हैं कि किसको हटाना है। यह सूचना प्रणाली आपको जितने चाहें उतने स्टैक करने देगी और एनीमेशन पूरा होने पर वे चली जाएगी। मैं एनीमेशन ईवेंट में हुकिंग कर रहा हूं और जब यह खत्म होता है तो मैं नोटिफिकेशन निकालने के लिए कुछ कोड को ट्रिगर करता हूं। मैं भी एक कॉलबैक टाइमआउट सेट करता हूं, ताकि एनीमेशन कॉलबैक में आग न लगने पाए।

अधिसूचना-actions.ts

import { USER_SYSTEM_NOTIFICATION } from '../constants/action-types';

interface IDispatchType {
    type: string;
    payload?: any;
    remove?: Symbol;
}

export const notifySuccess = (message: any, duration?: number) => {
    return (dispatch: Function) => {
        dispatch({ type: USER_SYSTEM_NOTIFICATION, payload: { isSuccess: true, message, notify_id: Symbol(), duration } } as IDispatchType);
    };
};

export const notifyFailure = (message: any, duration?: number) => {
    return (dispatch: Function) => {
        dispatch({ type: USER_SYSTEM_NOTIFICATION, payload: { isSuccess: false, message, notify_id: Symbol(), duration } } as IDispatchType);
    };
};

export const clearNotification = (notifyId: Symbol) => {
    return (dispatch: Function) => {
        dispatch({ type: USER_SYSTEM_NOTIFICATION, remove: notifyId } as IDispatchType);
    };
};

अधिसूचना-reducer.ts

const defaultState = {
    userNotifications: []
};

export default (state: ISystemNotificationReducer = defaultState, action: IDispatchType) => {
    switch (action.type) {
        case USER_SYSTEM_NOTIFICATION:
            const list: ISystemNotification[] = _.clone(state.userNotifications) || [];
            if (_.has(action, 'remove')) {
                const key = parseInt(_.findKey(list, (n: ISystemNotification) => n.notify_id === action.remove));
                if (key) {
                    // mutate list and remove the specified item
                    list.splice(key, 1);
                }
            } else {
                list.push(action.payload);
            }
            return _.assign({}, state, { userNotifications: list });
    }
    return state;
};

app.tsx

आपके आवेदन के लिए आधार रेंडर में आप सूचनाएँ प्रस्तुत करेंगे

render() {
    const { systemNotifications } = this.props;
    return (
        <div>
            <AppHeader />
            <div className="user-notify-wrap">
                { _.get(systemNotifications, 'userNotifications') && Boolean(_.get(systemNotifications, 'userNotifications.length'))
                    ? _.reverse(_.map(_.get(systemNotifications, 'userNotifications', []), (n, i) => <UserNotification key={i} data={n} clearNotification={this.props.actions.clearNotification} />))
                    : null
                }
            </div>
            <div className="content">
                {this.props.children}
            </div>
        </div>
    );
}

उपयोगकर्ता के notification.tsx

उपयोगकर्ता अधिसूचना वर्ग

/*
    Simple notification class.

    Usage:
        <SomeComponent notifySuccess={this.props.notifySuccess} notifyFailure={this.props.notifyFailure} />
        these two functions are actions and should be props when the component is connect()ed

    call it with either a string or components. optional param of how long to display it (defaults to 5 seconds)
        this.props.notifySuccess('it Works!!!', 2);
        this.props.notifySuccess(<SomeComponentHere />, 15);
        this.props.notifyFailure(<div>You dun goofed</div>);

*/

interface IUserNotifyProps {
    data: any;
    clearNotification(notifyID: symbol): any;
}

export default class UserNotify extends React.Component<IUserNotifyProps, {}> {
    public notifyRef = null;
    private timeout = null;

    componentDidMount() {
        const duration: number = _.get(this.props, 'data.duration', '');
       
        this.notifyRef.style.animationDuration = duration ? `${duration}s` : '5s';

        
        // fallback incase the animation event doesn't fire
        const timeoutDuration = (duration * 1000) + 500;
        this.timeout = setTimeout(() => {
            this.notifyRef.classList.add('hidden');
            this.props.clearNotification(_.get(this.props, 'data.notify_id') as symbol);
        }, timeoutDuration);

        TransitionEvents.addEndEventListener(
            this.notifyRef,
            this.onAmimationComplete
        );
    }
    componentWillUnmount() {
        clearTimeout(this.timeout);

        TransitionEvents.removeEndEventListener(
            this.notifyRef,
            this.onAmimationComplete
        );
    }
    onAmimationComplete = (e) => {
        if (_.get(e, 'animationName') === 'fadeInAndOut') {
            this.props.clearNotification(_.get(this.props, 'data.notify_id') as symbol);
        }
    }
    handleCloseClick = (e) => {
        e.preventDefault();
        this.props.clearNotification(_.get(this.props, 'data.notify_id') as symbol);
    }
    assignNotifyRef = target => this.notifyRef = target;
    render() {
        const {data, clearNotification} = this.props;
        return (
            <div ref={this.assignNotifyRef} className={cx('user-notification fade-in-out', {success: data.isSuccess, failure: !data.isSuccess})}>
                {!_.isString(data.message) ? data.message : <h3>{data.message}</h3>}
                <div className="close-message" onClick={this.handleCloseClick}>+</div>
            </div>
        );
    }
}

1
"स्टोर के माध्यम से"? मुझे लगता है, Im के बारे में कुछ महत्वपूर्ण सबक याद आ रही है: D उत्तर और कोड के लिए धन्यवाद, लेकिन क्या आपको नहीं लगता कि यह एक साधारण त्रुटि संदेश प्रदर्शन घटक के लिए गंभीरता से ओवरकिल है? बच्चे पर परिभाषित एक कार्रवाई को संभालने के लिए माता-पिता की जिम्मेदारी नहीं होनी चाहिए ...
सिपाही

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

ठीक है, यदि आप कृपया कोड टुकड़े के कुछ सूचक प्राप्त करने के लिए खुश हो। जब मैंने फ्लक्स और रेड्यूक दोनों के बारे में थोड़ा पढ़ा है, तो कोड के उस टुकड़े पर वापस जाओ!
सिपाही

ठीक है, मुझे लगता है कि मैं इसे करने का एक रास्ता दिखाते हुए एक साधारण गीथूब रेपो बनाऊंगा। पिछले एक मैंने किया था कि मैंने सीएसएस एनिमेशन का उपयोग फीका तत्व को फीका करने के लिए किया था जो स्ट्रिंग या html तत्वों को प्रस्तुत कर सकता था और फिर जब एनीमेशन पूरा हो गया तो मैंने उस के लिए सुनने के लिए जावास्क्रिप्ट का उपयोग किया और फिर स्वयं को हटा दें (डोम से हटा दें) जब या तो एनीमेशन समाप्त हो गया है या आपने खारिज बटन पर क्लिक किया है।
जॉन रूडेल

कृपया, अगर यह मेरे जैसे अन्य लोगों की मदद कर सकता है जो रिएक्ट के दर्शन को समझने के लिए थोड़ा संघर्ष करते हैं। इसके अलावा, यदि आपने इसके लिए एक git रेपो रखा है, तो समय के लिए अपने कुछ बिंदुओं के साथ भाग लेना मुझे अच्छा लगेगा! चलो एक सौ अंक (हालांकि 2 दिनों में उपलब्ध इनाम) कहते हैं
सिपाही

25

के बजाय का उपयोग करने का

ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(this).parentNode);

प्रयोग करके देखें

ReactDOM.unmountComponentAtNode(document.getElementById('root'));

क्या किसी ने रिएक्ट 15 के साथ यह कोशिश की है? यह दोनों संभावित-उपयोगी और संभवतः एक विरोधी-पैटर्न लगता है।
द यूटरसाइड

4
@theUtherSide यह प्रतिक्रिया में एक विरोधी पैटर्न है। प्रतिक्रिया डॉक्स आपको राज्य / सहारा के माध्यम से माता-पिता से एक बच्चे को अनमाउंट करने की सलाह देते हैं
जॉन रूडेल

1
क्या होगा यदि घटक अनमाउंट हो रहा है, लेकिन आपके रिएक्ट ऐप की जड़ नहीं बल्कि रूट एलिमेंट को बदला जा रहा है? उदाहरण के लिए <div id="c1"><div id="c2"><div id="react-root" /></div></div>। क्या होगा अगर आंतरिक पाठ को c1प्रतिस्थापित किया जाए?
फ्लिपडाउट

1
यह उपयोगी है अगर आप अपने रूट कंपोनेंट को अनमाउंट करना चाहते हैं, खासकर यदि आपके पास एक रिएक्शन ऐप है जो नॉन-रिएक्शन ऐप में रहता है। मुझे इसका उपयोग करना पड़ा क्योंकि मैं एक अन्य ऐप द्वारा नियंत्रित मोडल के अंदर प्रतिक्रिया को प्रस्तुत करना चाहता था, और उनके मॉडल में करीब बटन होते हैं जो मोडल को छिपा देंगे लेकिन मेरी प्रतिक्रिया अभी भी घुड़सवार रहेगी। reactjs.org/blog/2015/10/01/react-render-and-top-level-api.html
Abba

10

ज्यादातर मामलों में, यह तत्व को छिपाने के लिए पर्याप्त है, उदाहरण के लिए इस तरह से:

export default class ErrorBoxComponent extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            isHidden: false
        }
    }

    dismiss() {
        this.setState({
            isHidden: true
        })
    }

    render() {
        if (!this.props.error) {
            return null;
        }

        return (
            <div data-alert className={ "alert-box error-box " + (this.state.isHidden ? 'DISPLAY-NONE-CLASS' : '') }>
                { this.props.error }
                <a href="#" className="close" onClick={ this.dismiss.bind(this) }>&times;</a>
            </div>
        );
    }
}

या आप इस तरह के मूल घटक के माध्यम से रेंडर / रेंडर / प्रस्तुत नहीं कर सकते हैं

export default class ParentComponent extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            isErrorShown: true
        }
    }

    dismiss() {
        this.setState({
            isErrorShown: false
        })
    }

    showError() {
        if (this.state.isErrorShown) {
            return <ErrorBox 
                error={ this.state.error }
                dismiss={ this.dismiss.bind(this) }
            />
        }

        return null;
    }

    render() {

        return (
            <div>
                { this.showError() }
            </div>
        );
    }
}

export default class ErrorBoxComponent extends React.Component {
    dismiss() {
        this.props.dismiss();
    }

    render() {
        if (!this.props.error) {
            return null;
        }

        return (
            <div data-alert className="alert-box error-box">
                { this.props.error }
                <a href="#" className="close" onClick={ this.dismiss.bind(this) }>&times;</a>
            </div>
        );
    }
}

अंत में, html नोड को हटाने का एक तरीका है, लेकिन मैं वास्तव में नहीं जानता कि यह एक अच्छा विचार है। हो सकता है कि आंतरिक से प्रतिक्रिया जानने वाला कोई व्यक्ति इस बारे में कुछ कहेगा।

export default class ErrorBoxComponent extends React.Component {
    dismiss() {
        this.el.remove();
    }

    render() {
        if (!this.props.error) {
            return null;
        }

        return (
            <div data-alert className="alert-box error-box" ref={ (el) => { this.el = el} }>
                { this.props.error }
                <a href="#" className="close" onClick={ this.dismiss.bind(this) }>&times;</a>
            </div>
        );
    }
}

लेकिन, इस मामले में कि मैं एक बच्चे को अनमाउंट करना चाहता हूं जो कि बच्चों की सूची के अंदर है ... अगर मैं उस सूची में उसी कुंजी के साथ एक क्लोन किए गए घटक को बदलना चाहता हूं तो मैं क्या कर सकता हूं?
राददेव

1
जैसा कि मैं समझता हूँ कि आप ऐसा कुछ करना चाहते हैं: document.getElementById (CHILD_NODE_)) -> -remove (); -> document.getElementById (PARENT_NODE_ID) -> .appendChild (NEW_NODE)? क्या मैं सही हू? इसके बारे में भूल जाओ। यह प्रतिक्रिया नहीं है। शर्त रेंडरिंग के लिए कंपोनेंट स्टेट का उपयोग करें
साशा कोस

2

मैं अब तक लगभग 10 बार इस पद पर आ चुका हूं और मैं यहां अपने दो सेंट छोड़ना चाहता था। आप इसे सशर्त रूप से अनमाउंट कर सकते हैं।

if (renderMyComponent) {
  <MyComponent props={...} />
}

आपको केवल इसे अनमाउंट करने के लिए इसे DOM से निकालना है।

जब तक renderMyComponent = true, घटक प्रस्तुत करेगा। यदि आप सेट करते हैं renderMyComponent = false, तो यह DOM से अनमाउंट होगा।


-1

यह सभी स्थितियों में उचित नहीं है लेकिन आप return falseघटक के अंदर सशर्त रूप से स्वयं कर सकते हैं यदि कोई निश्चित मापदंड है या नहीं मिला है।

यह घटक को अनमाउंट नहीं करता है, लेकिन यह सभी प्रदान की गई सामग्री को हटा देता है। यह केवल मेरे दिमाग में बुरा होगा, अगर आपके पास घटक में घटना श्रोता हैं जिन्हें तब हटा दिया जाना चाहिए जब घटक की आवश्यकता नहीं है।

import React, { Component } from 'react';

export default class MyComponent extends Component {
    constructor(props) {
        super(props);

        this.state = {
            hideComponent: false
        }
    }

    closeThis = () => {
        this.setState(prevState => ({
            hideComponent: !prevState.hideComponent
        })
    });

    render() {
        if (this.state.hideComponent === true) {return false;}

        return (
            <div className={`content`} onClick={() => this.closeThis}>
                YOUR CODE HERE
            </div>
        );
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.