प्रतिक्रिया - एक एकल घटक का माउंट और अनमाउंट


97

यह सरल कुछ आसानी से पूरा किया जाना चाहिए, फिर भी मैं अपने बालों को बाहर खींच रहा हूं कि यह कितना जटिल है।

मैं केवल एक प्रतिक्रिया घटक के बढ़ते और अनमाउंटिंग को चेतन करना चाहता हूं, बस। यहाँ मैंने जो अभी तक कोशिश की है और क्यों प्रत्येक समाधान काम नहीं करेगा:

  1. ReactCSSTransitionGroup - मैं सीएसएस कक्षाओं का उपयोग नहीं कर रहा हूं, यह सभी जेएस शैली है, इसलिए यह काम नहीं करेगा।
  2. ReactTransitionGroup- यह निचले स्तर का एपीआई बहुत अच्छा है, लेकिन आपको एनीमेशन पूरा होने पर कॉलबैक का उपयोग करने की आवश्यकता होती है, इसलिए बस सीएसएस संक्रमण का उपयोग करने से यहां काम नहीं होगा। हमेशा एनीमेशन लाइब्रेरी होती हैं, जो अगले बिंदु तक ले जाती हैं:
  3. GreenSock - व्यवसाय के उपयोग के लिए लाइसेंसिंग बहुत प्रतिबंधात्मक है IMO।
  4. रिएक्ट मोशन - यह बहुत अच्छा लगता है, लेकिन TransitionMotionमुझे जो चाहिए उसके लिए बेहद भ्रमित और अति जटिल है।
  5. बेशक मैं सिर्फ सामग्री यूआई की तरह चालबाजी कर सकता हूं, जहां तत्व प्रदान किए जाते हैं लेकिन छिपे हुए हैं ( left: -10000px) रहते हैं, लेकिन मैं उस मार्ग पर नहीं जाता हूं। मैं इसे हैक करने वाला मानता हूं, और मैं चाहता हूं कि मेरे कंपोनेंट्स बेपर्दा हो जाएं, ताकि वे साफ हो जाएं और डीओएम को बंद न करें।

मैं ऐसा कुछ चाहता हूं जिसे लागू करना आसान हो। माउंट पर, शैलियों का एक सेट चेतन करें; शैलियों के समान (या अन्य) सेट को अनमाउंट करें। किया हुआ। यह कई प्लेटफार्मों पर उच्च प्रदर्शन होना चाहिए।

मैंने यहां एक ईंट की दीवार से टकराया है। अगर मुझे कुछ याद आ रहा है और ऐसा करने का एक आसान तरीका है, तो मुझे बताएं।


हम यहां किस तरह के एनीमेशन की बात कर रहे हैं?
प्राणेश रवि

बस कुछ सरल है, जैसे एक सीएसएस अपारदर्शिता फीका और एकtransform: scale
ffxsam

बिंदु 1 और 2 मुझे भ्रमित करता है। आप किस तरह के एनिमेशन का उपयोग कर रहे हैं? जेएस संक्रमण या सीएसएस संक्रमण?
प्राणेश रवि

1
सीएसएस शैलियों / वर्गों (जैसे .thing { color: #fff; }) को जेएस शैलियों ( const styles = { thing: { color: '#fff' } }) के साथ भ्रमित न करें
ffxsam

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

जवाबों:


102

यह थोड़ा लंबा है, लेकिन मैंने इस एनीमेशन को प्राप्त करने के लिए सभी मूल घटनाओं और विधियों का उपयोग किया है। नहीं ReactCSSTransitionGroup, ReactTransitionGroupऔर आदि

चीजें जो मैंने उपयोग की हैं

  • जीवनचक्र विधियों को फिर से शुरू करें
  • onTransitionEnd प्रतिस्पर्धा

यह कैसे काम करता है

  • माउंट प्रोप के आधार पर तत्व को माउंट करें ( mounted) और डिफ़ॉल्ट शैली के साथ ( opacity: 0)
  • माउंट या अपडेट के बाद, टाइमआउट (इसे बनाने के लिए) को स्टाइल ( ) में बदलने के लिए componentDidMount( componentWillReceivePropsआगे के अपडेट के लिए) का उपयोग करें opacity: 1
  • अनमाउंट के दौरान, घटक के लिए प्रोप को अनमाउंट की पहचान करें, शैली को फिर से बदलें ( opacity: 0), onTransitionEndडोम से तत्व को हटा दें।

चक्र जारी रखें।

कोड के माध्यम से जाओ, तुम समझ जाओगे। यदि किसी स्पष्टीकरण की आवश्यकता है, तो कृपया एक टिप्पणी छोड़ दें।

उम्मीद है की यह मदद करेगा।

class App extends React.Component{
  constructor(props) {
    super(props)
    this.transitionEnd = this.transitionEnd.bind(this)
    this.mountStyle = this.mountStyle.bind(this)
    this.unMountStyle = this.unMountStyle.bind(this)
    this.state ={ //base css
      show: true,
      style :{
        fontSize: 60,
        opacity: 0,
        transition: 'all 2s ease',
      }
    }
  }
  
  componentWillReceiveProps(newProps) { // check for the mounted props
    if(!newProps.mounted)
      return this.unMountStyle() // call outro animation when mounted prop is false
    this.setState({ // remount the node when the mounted prop is true
      show: true
    })
    setTimeout(this.mountStyle, 10) // call the into animation
  }
  
  unMountStyle() { // css for unmount animation
    this.setState({
      style: {
        fontSize: 60,
        opacity: 0,
        transition: 'all 1s ease',
      }
    })
  }
  
  mountStyle() { // css for mount animation
    this.setState({
      style: {
        fontSize: 60,
        opacity: 1,
        transition: 'all 1s ease',
      }
    })
  }
  
  componentDidMount(){
    setTimeout(this.mountStyle, 10) // call the into animation
  }
  
  transitionEnd(){
    if(!this.props.mounted){ // remove the node on transition end when the mounted prop is false
      this.setState({
        show: false
      })
    }
  }
  
  render() {
    return this.state.show && <h1 style={this.state.style} onTransitionEnd={this.transitionEnd}>Hello</h1> 
  }
}

class Parent extends React.Component{
  constructor(props){
    super(props)
    this.buttonClick = this.buttonClick.bind(this)
    this.state = {
      showChild: true,
    }
  }
  buttonClick(){
    this.setState({
      showChild: !this.state.showChild
    })
  }
  render(){
    return <div>
        <App onTransitionEnd={this.transitionEnd} mounted={this.state.showChild}/>
        <button onClick={this.buttonClick}>{this.state.showChild ? 'Unmount': 'Mount'}</button>
      </div>
  }
}

ReactDOM.render(<Parent />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-with-addons.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>


इसके लिए धन्यवाद! आपने कहां से सीखा onTransitionEnd? मैं इसे रिएक्ट डॉक्स में नहीं देखता हूं।
ffxsam

@ffxsam facebook.github.io/react/docs/events.html यह संक्रमण की घटनाओं के तहत है।
प्राणेश रवि

1
आपको कैसे पता चला कि हालांकि यह क्या हुआ, प्रलेखन कुछ भी स्पष्ट नहीं करता है। एक और सवाल: आपको कैसे पता चला कि आप componentWillReceivePropsकुछ वापस कर सकते हैं? मैं उस पर और कहां पढ़ सकता हूं?
22

1
@ffxsam onTransitionEnd एक देशी जावास्क्रिप्ट घटना है। आप इसके बारे में google कर सकते हैं। facebook.github.io/react/docs/… आपको कंपोनेंटलीवरसिवप्रॉप्स के बारे में एक विचार देगा।
प्राणेश रवि

7
BTW मुझे लगता है कि आपके कोड में कोई गलती है। आपके Parentघटक में, आप संदर्भ देते हैंthis.transitionEnd
ffxsam 20

14

प्राणेश के उत्तर से प्राप्त ज्ञान का उपयोग करते हुए, मैं एक वैकल्पिक समाधान के साथ आया हूं जो कि विन्यास योग्य और पुन: प्रयोज्य है:

const AnimatedMount = ({ unmountedStyle, mountedStyle }) => {
  return (Wrapped) => class extends Component {
    constructor(props) {
      super(props);
      this.state = {
        style: unmountedStyle,
      };
    }

    componentWillEnter(callback) {
      this.onTransitionEnd = callback;
      setTimeout(() => {
        this.setState({
          style: mountedStyle,
        });
      }, 20);
    }

    componentWillLeave(callback) {
      this.onTransitionEnd = callback;
      this.setState({
        style: unmountedStyle,
      });
    }

    render() {
      return <div
        style={this.state.style}
        onTransitionEnd={this.onTransitionEnd}
      >
        <Wrapped { ...this.props } />
      </div>
    }
  }
};

उपयोग:

import React, { PureComponent } from 'react';

class Thing extends PureComponent {
  render() {
    return <div>
      Test!
    </div>
  }
}

export default AnimatedMount({
  unmountedStyle: {
    opacity: 0,
    transform: 'translate3d(-100px, 0, 0)',
    transition: 'opacity 250ms ease-out, transform 250ms ease-out',
  },
  mountedStyle: {
    opacity: 1,
    transform: 'translate3d(0, 0, 0)',
    transition: 'opacity 1.5s ease-out, transform 1.5s ease-out',
  },
})(Thing);

और अंत में, एक अन्य घटक की renderविधि में:

return <div>
  <ReactTransitionGroup>
    <Thing />
  </ReactTransitionGroup>
</div>

1
और आप @ffxsam को कैसे माउंट / अनमाउंट करते हैं?

कैसे कहा जाता है componentWillLeave()और में हो componentWillEnter()रही है AnimatedMount?
Rokit

मेरे लिए काम नहीं करता है, यहाँ मेरा सैंडबॉक्स: कोडैंडबॉक्स.io
s

11

घटक के अनमाउंट चरण में देरी के लिए इस पोस्ट के आधार पर नए हुक एपीआई (टाइपस्क्रिप्ट के साथ) का उपयोग करके मेरा समाधान यहां दिया गया है :

function useDelayUnmount(isMounted: boolean, delayTime: number) {
    const [ shouldRender, setShouldRender ] = useState(false);

    useEffect(() => {
        let timeoutId: number;
        if (isMounted && !shouldRender) {
            setShouldRender(true);
        }
        else if(!isMounted && shouldRender) {
            timeoutId = setTimeout(
                () => setShouldRender(false), 
                delayTime
            );
        }
        return () => clearTimeout(timeoutId);
    }, [isMounted, delayTime, shouldRender]);
    return shouldRender;
}

उपयोग:

const Parent: React.FC = () => {
    const [ isMounted, setIsMounted ] = useState(true);
    const shouldRenderChild = useDelayUnmount(isMounted, 500);
    const mountedStyle = {opacity: 1, transition: "opacity 500ms ease-in"};
    const unmountedStyle = {opacity: 0, transition: "opacity 500ms ease-in"};

    const handleToggleClicked = () => {
        setIsMounted(!isMounted);
    }

    return (
        <>
            {shouldRenderChild && 
                <Child style={isMounted ? mountedStyle : unmountedStyle} />}
            <button onClick={handleToggleClicked}>Click me!</button>
        </>
    );
}

CodeSandbox लिंक।


1
सुरुचिपूर्ण समाधान, बहुत अच्छा होगा अगर आपने कुछ टिप्पणियां जोड़ी हैं :)
वेबवूमन

यह भी क्यों जावास्क्रिप्ट के विस्तार में अच्छी तरह से काम करता है के बाद से typecrypt के विस्तार का उपयोग करें?
वेबवैन

यह भी कि आपका कंसोल रिटर्न "नेमस्पेस NodeJS टाइमआउट नहीं ढूंढ सकता है"
वेबवूमन

1
@Webwoman आपकी टिप्पणियों के लिए धन्यवाद। मैं "NodeJS टाइमआउट" के साथ आपकी रिपोर्ट की गई समस्या को फिर से नहीं बना सकता, जवाब के नीचे मेरा कोडसैंडबॉक्स लिंक देखें। टाइपस्क्रिप्ट के बारे में, मैं व्यक्तिगत रूप से जावास्क्रिप्ट पर इसका उपयोग करना पसंद करता हूं, हालांकि दोनों निश्चित रूप से व्यवहार्य हैं।
डेकले

9

मैंने अपने काम के दौरान इस समस्या को गिना, और जैसा कि यह सरल था, यह वास्तव में रिएक्ट में नहीं है। एक सामान्य परिदृश्य में जहां आप कुछ इस तरह प्रस्तुत करते हैं:

this.state.show ? {childen} : null;

जैसे- this.state.showजैसे बच्चे बदलते हैं / ठीक-ठीक उन्मुक्त हो जाते हैं।

मेरे द्वारा लिया गया एक दृष्टिकोण एक आवरण घटक बना रहा है Animateऔर इसका उपयोग करता है

<Animate show={this.state.show}>
  {childen}
</Animate>

अब this.state.showपरिवर्तनों के रूप में , हम getDerivedStateFromProps(componentWillReceiveProps)एनिमेशन में प्रदर्शन करने के लिए मध्यवर्ती परिवर्तन चरणों का निर्माण कर सकते हैं।

एक मंच चक्र इस तरह लग सकता है

हम स्टैटिक स्टेज से शुरू करते हैं जब बच्चे माउंटेड या अनमाउंट होते हैं।

एक बार जब हम showध्वज परिवर्तनों का पता लगा लेते हैं, तो हम Prep Stage में प्रवेश करते हैं, जहाँ हम आवश्यक गुणों की गणना करते हैं जैसे कि heightऔर widthसे ReactDOM.findDOMNode.getBoundingClientRect()

फिर चेतन अवस्था में प्रवेश करके हम 0 से गणना की गई मानों (या यदि 0) के लिए ऊंचाई, चौड़ाई और अस्पष्टता को बदलने के लिए सीएसएस संक्रमण का उपयोग कर सकते हैं।

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

बहुत अधिक विवरण हैं कि कैसे चरण सुचारू रूप से स्थानांतरित होते हैं लेकिन यह समग्र विचार हो सकता है :)

यदि कोई दिलचस्पी रखता है, तो मैंने अपना समाधान साझा करने के लिए एक प्रतिक्रिया पुस्तकालय https://github.com/MingruiZhang/react-animate-mount बनाया । किसी भी प्रतिक्रिया का स्वागत :)


आपकी प्रतिक्रिया के लिए धन्यवाद, पहले कच्चे जवाब के लिए क्षमा करें। मैंने अपने उत्तर में अधिक विस्तार और एक आरेख जोड़ा है, आशा है कि यह दूसरों के लिए अधिक उपयोगी हो सकता है।
मिंगरु झांग

1
@MingruiZhang यह देखना अच्छा है कि आपने टिप्पणियों को सकारात्मक रूप से लिया है और अपने उत्तर में सुधार किया है। यह देखना बहुत ताज़ा है। अच्छा कार्य।
बग्स

6

मुझे लगता है कि का उपयोग कर Transitionसे react-transition-groupशायद बढ़ते / unmounting ट्रैक करने के लिए सबसे आसान तरीका है। यह अविश्वसनीय रूप से लचीला है। मैं कुछ वर्गों का उपयोग कर रहा हूं यह दिखाने के लिए कि यह कितना आसान है लेकिन आप निश्चित रूप से अपने स्वयं के जेएस एनिमेशन का उपयोग कर सकते हैंaddEndListener जो कि जीएसएपी का उपयोग करने के साथ-साथ मेरे पास बहुत सारी किस्मत है।

सैंडबॉक्स: https://codesandbox.io/s/k9xl9mkx2o

और यहाँ मेरा कोड है।

import React, { useState } from "react";
import ReactDOM from "react-dom";
import { Transition } from "react-transition-group";
import styled from "styled-components";

const H1 = styled.h1`
  transition: 0.2s;
  /* Hidden init state */
  opacity: 0;
  transform: translateY(-10px);
  &.enter,
  &.entered {
    /* Animate in state */
    opacity: 1;
    transform: translateY(0px);
  }
  &.exit,
  &.exited {
    /* Animate out state */
    opacity: 0;
    transform: translateY(-10px);
  }
`;

const App = () => {
  const [show, changeShow] = useState(false);
  const onClick = () => {
    changeShow(prev => {
      return !prev;
    });
  };
  return (
    <div>
      <button onClick={onClick}>{show ? "Hide" : "Show"}</button>
      <Transition mountOnEnter unmountOnExit timeout={200} in={show}>
        {state => {
          let className = state;
          return <H1 className={className}>Animate me</H1>;
        }}
      </Transition>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

1
यदि आप स्टाइल घटकों का उपयोग करते हैं, तो आप बस स्टाइल घटक के अंदर showप्रोप H1और सभी तर्क कर सकते हैं। जैसे ...animation: ${({ show }) => show ? entranceKeyframes : exitKeyframes} 300ms ease-out forwards;
एलेक्सा

2

फ्रैमर गति

Npm से फ्रैमर-मोशन स्थापित करें।

import { motion, AnimatePresence } from "framer-motion"

export const MyComponent = ({ isVisible }) => (
  <AnimatePresence>
    {isVisible && (
      <motion.div
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
      />
    )}
  </AnimatePresence>
)

1

प्रतिक्रिया-गति पर विचार करने वालों के लिए, एकल घटक को एनिमेट करना, जब यह mounts और अनमाउंट्स सेट करने के लिए भारी हो सकता है।

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

उपयोग:

import Transition from 'react-motion-ui-pack'

<Transition
  enter={{ opacity: 1, translateX: 0 }}
  leave={{ opacity: 0, translateX: -100 }}
  component={false}
>
  { this.state.show &&
      <div key="hello">
        Hello
      </div>
  }
</Transition>

दर्ज करें परिभाषित करता है कि घटक की अंतिम स्थिति क्या होनी चाहिए; छुट्टी वह शैली है जो घटक के अनमाउंट होने पर लागू की जाती है।

आप पा सकते हैं कि एक बार जब आप यूआई पैक का एक-दो बार उपयोग कर लेते हैं, तो प्रतिक्रिया-गति लाइब्रेरी अब अधिक चुनौतीपूर्ण नहीं हो सकती है।


प्रोजेक्ट अब बनाए नहीं रखा गया है (2018)
Micros


1

यह उस CSSTransitionघटक का उपयोग करके आसानी से किया जा सकता है react-transition-group, जो आपके द्वारा उल्लिखित पुस्तकालयों की तरह है। चाल की जरूरत है कि आपको CSSTransition घटक को बिना दिखाने / छिपाने के तंत्र के बिना लपेटने की आवश्यकता है जैसे कि आप आमतौर पर .ie {show && <Child>}...अन्यथा आप एनीमेशन छिपा रहे हैं और यह काम नहीं करेगा। उदाहरण:

ParentComponent.js

import React from 'react';
import {CSSTransition} from 'react-transition-group';

function ParentComponent({show}) {
return (
  <CSSTransition classes="parentComponent-child" in={show} timeout={700}>
    <ChildComponent>
  </CSSTransition>
)}


ParentComponent.css

// animate in
.parentComponent-child-enter {
  opacity: 0;
}
.parentComponent-child-enter-active {
  opacity: 1;
  transition: opacity 700ms ease-in;
}
// animate out
.parentComponent-child-exit {
  opacity: 1;
}
.parentComponent-child-exit-active {
  opacity: 0;
  transition: opacity 700ms ease-in;
}

0

यहाँ मेरे 2cents: उसके समाधान के लिए @deckele को धन्यवाद। मेरा समाधान उसके आधार पर है, यह राज्य का घटक संस्करण है, पूरी तरह से पुन: प्रयोज्य है।

: मेरे सैंडबॉक्स यहां https://codesandbox.io/s/302mkm1m

यहाँ मेरे snippet.js:

import ReactDOM from "react-dom";
import React, { Component } from "react";
import style from  "./styles.css"; 

class Tooltip extends Component {

  state = {
    shouldRender: false,
    isMounted: true,
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (this.state.shouldRender !== nextState.shouldRender) {
      return true
    }
    else if (this.state.isMounted !== nextState.isMounted) {
      console.log("ismounted!")
      return true
    }
    return false
  }
  displayTooltip = () => {
    var timeoutId;
    if (this.state.isMounted && !this.state.shouldRender) {
      this.setState({ shouldRender: true });
    } else if (!this.state.isMounted && this.state.shouldRender) {
      timeoutId = setTimeout(() => this.setState({ shouldRender: false }), 500);
      () => clearTimeout(timeoutId)
    }
    return;
  }
  mountedStyle = { animation: "inAnimation 500ms ease-in" };
  unmountedStyle = { animation: "outAnimation 510ms ease-in" };

  handleToggleClicked = () => {
    console.log("in handleToggleClicked")
    this.setState((currentState) => ({
      isMounted: !currentState.isMounted
    }), this.displayTooltip());
  };

  render() {
    var { children } = this.props
    return (
      <main>
        {this.state.shouldRender && (
          <div className={style.tooltip_wrapper} >
            <h1 style={!(this.state.isMounted) ? this.mountedStyle : this.unmountedStyle}>{children}</h1>
          </div>
        )}

        <style>{`

           @keyframes inAnimation {
    0% {
      transform: scale(0.1);
      opacity: 0;
    }
    60% {
      transform: scale(1.2);
      opacity: 1;
    }
    100% {
      transform: scale(1);  
    }
  }

  @keyframes outAnimation {
    20% {
      transform: scale(1.2);
    }
    100% {
      transform: scale(0);
      opacity: 0;
    }
  }
          `}
        </style>
      </main>
    );
  }
}


class App extends Component{

  render(){
  return (
    <div className="App"> 
      <button onClick={() => this.refs.tooltipWrapper.handleToggleClicked()}>
        click here </button>
      <Tooltip
        ref="tooltipWrapper"
      >
        Here a children
      </Tooltip>
    </div>
  )};
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

0

यहां मैंने एक लोडिंग स्पिनर बनाते हुए 2019 में इसे कैसे हल किया। मैं प्रतिक्रियाशील कार्यात्मक घटकों का उपयोग कर रहा हूं।

मेरे पास एक पैरेंट ऐप कंपोनेंट है जिसमें चाइल्ड स्पिनर कंपोनेंट है।

ऐप में स्टेट है कि ऐप लोड हो रहा है या नहीं। जब एप्लिकेशन लोड हो रहा है, तो स्पिनर सामान्य रूप से प्रदान किया जाता है। जब एप्लिकेशन लोड नहीं हो रहा है ( isLoadingगलत है) तो स्पिनर को प्रोप के साथ प्रस्तुत किया जाता है shouldUnmount

App.js :

import React, {useState} from 'react';
import Spinner from './Spinner';

const App = function() {
    const [isLoading, setIsLoading] = useState(false);

    return (
        <div className='App'>
            {isLoading ? <Spinner /> : <Spinner shouldUnmount />}
        </div>
    );
};

export default App;

स्पिनर के पास यह स्थिति है कि वह छिपा हुआ है या नहीं। शुरुआत में, डिफ़ॉल्ट सहारा और स्थिति के साथ, स्पिनर को सामान्य रूप से प्रदान किया जाता है। Spinner-fadeInवर्ग उत्साहित उस में fading। जब स्पिनर प्रोप प्राप्त करता है shouldUnmountइसके साथ rendersSpinner-fadeOut बजाय वर्ग, यह पता fading एनिमेट।

हालाँकि मैं यह भी चाहता था कि घटक के मुरझाने के बाद उसे हटा दिया जाए।

इस बिंदु पर, मैंने onAnimationEndऊपर @ pranesh-ravi के समाधान के समान रिएक्ट सिंथेटिक घटना का उपयोग करने की कोशिश की , लेकिन यह काम नहीं किया। इसके बजाय मैंने setTimeoutराज्य को सेट करने के लिए एनीमेशन के समान लंबाई में देरी के साथ छिपाया। स्पिनर देरी के साथ अद्यतन करेगा isHidden === true, और कुछ भी प्रदान नहीं किया जाएगा।

यहां कुंजी यह है कि माता-पिता बच्चे को अनमाउंट नहीं करते हैं, यह बच्चे को बताता है कि कब उसे अनमाउंट करना है, और बच्चा अपने अनमाउंटिंग व्यवसाय की देखभाल करने के बाद खुद को अनमाउंट करता है।

स्पिनर.जेएस :

import React, {useState} from 'react';
import './Spinner.css';

const Spinner = function(props) {
    const [isHidden, setIsHidden] = useState(false);

    if(isHidden) {
        return null

    } else if(props.shouldUnmount) {
        setTimeout(setIsHidden, 500, true);
        return (
            <div className='Spinner Spinner-fadeOut' />
        );

    } else {
        return (
            <div className='Spinner Spinner-fadeIn' />
        );
    }
};

export default Spinner;

Spinner.css:

.Spinner {
    position: fixed;
    display: block;
    z-index: 999;
    top: 50%;
    left: 50%;
    margin: -40px 0 0 -20px;
    height: 40px;
    width: 40px;
    border: 5px solid #00000080;
    border-left-color: #bbbbbbbb;
    border-radius: 40px;
}

.Spinner-fadeIn {
    animation: 
        rotate 1s linear infinite,
        fadeIn .5s linear forwards;
}

.Spinner-fadeOut {
    animation: 
        rotate 1s linear infinite,
        fadeOut .5s linear forwards;
}

@keyframes fadeIn {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}
@keyframes fadeOut {
    0% {
        opacity: 1;
    }
    100% {
        opacity: 0;
    }
}

@keyframes rotate {
    100% {
        transform: rotate(360deg);
    }
}

0

मुझे एकल घटक एनिमेशन की सख्त जरूरत थी। मैं रिएक्ट मोशन का उपयोग करके थक गया लेकिन मैं इस तरह के एक तुच्छ मुद्दे के लिए अपने बालों को खींच रहा था .. (आई)। कुछ googling के बाद मैं उनके git रेपो पर इस पोस्ट के पार आया। आशा है कि यह किसी की मदद करता है ..

क्रेडिट से भी संदर्भित । यह मेरे लिए अब तक का काम करता है। मेरा उपयोग मामला लोड और अनलोड के मामले में चेतन और अनमाउंट करने के लिए एक मोडल था।

class Example extends React.Component {
  constructor() {
    super();
    
    this.toggle = this.toggle.bind(this);
    this.onRest = this.onRest.bind(this);

    this.state = {
      open: true,
      animating: false,
    };
  }
  
  toggle() {
    this.setState({
      open: !this.state.open,
      animating: true,
    });
  }
  
  onRest() {
    this.setState({ animating: false });
  }
  
  render() {
    const { open, animating } = this.state;
    
    return (
      <div>
        <button onClick={this.toggle}>
          Toggle
        </button>
        
        {(open || animating) && (
          <Motion
            defaultStyle={open ? { opacity: 0 } : { opacity: 1 }}
            style={open ? { opacity: spring(1) } : { opacity: spring(0) }}
            onRest={this.onRest}
          >
            {(style => (
              <div className="box" style={style} />
            ))}
          </Motion>
        )}
      </div>
    );
  }
}


0

मुझे पता है कि यहां बहुत सारे उत्तर हैं, लेकिन मुझे अभी भी एक ऐसा नहीं मिला जो मेरी आवश्यकताओं के अनुरूप हो। मुझे चाहिए:

  • कार्यात्मक घटक
  • एक समाधान जो मेरे घटकों को आसानी से अंदर / बाहर करने की अनुमति देगा जब वे माउंटेड / अनमाउंट किए जाते हैं।

कई घंटे तक चलने के बाद, मेरे पास एक उपाय है कि मैं 90% काम करूंगा। मैंने नीचे दिए गए कोड में एक टिप्पणी ब्लॉक में सीमा लिखी है। मैं अभी भी एक बेहतर समाधान प्यार करता हूँ, लेकिन यह सबसे अच्छा मैंने पाया है, यहाँ अन्य समाधान भी शामिल है।

const TIMEOUT_DURATION = 80 // Just looked like best balance of silky smooth and stop delaying me.

// Wrap this around any views and they'll fade in and out when mounting /
// unmounting.  I tried using <ReactCSSTransitionGroup> and <Transition> but I
// could not get them to work.  There is one major limitation to this approach:
// If a component that's mounted inside of <Fade> has direct prop changes,
// <Fade> will think that it's a new component and unmount/mount it.  This
// means the inner component will fade out and fade in, and things like cursor
// position in forms will be reset. The solution to this is to abstract <Fade>
// into a wrapper component.

const Fade: React.FC<{}> = ({ children }) => {
  const [ className, setClassName ] = useState('fade')
  const [ newChildren, setNewChildren ] = useState(children)

  const effectDependency = Array.isArray(children) ? children : [children]

  useEffect(() => {
    setClassName('fade')

    const timerId = setTimeout(() => {
      setClassName('fade show')
      setNewChildren(children)
    }, TIMEOUT_DURATION)

    return () => {
      clearTimeout(timerId)
    }   

  }, effectDependency)

  return <Container fluid className={className + ' p-0'}>{newChildren}</Container>
}

यदि आपके पास एक घटक है जिसे आप / बाहर फीका करना चाहते हैं, तो इसे <Fade>Ex में लपेटें । <Fade><MyComponent/><Fade>

ध्यान दें कि यह react-bootstrapवर्ग के नाम और के लिए उपयोग करता है <Container/>, लेकिन दोनों को आसानी से कस्टम सीएसएस और एक नियमित पुराने के साथ बदला जा सकता है <div>


0

यदि मैं सीधे ( या के बजाय ) नोड को चेतन करने के लिए पुस्तकालय Velocityया उपयोग करता हूं , तो मुझे पता चला कि मैं एनीमेशन स्थिति और फ़ंक्शन प्रदान करने के लिए डिज़ाइन कर सकता हूंAnimeJScsssetTimeouthookononToggle एनीमेशन (उदा। Slidedown, फीका) बंद लात करने के लिए।

मूल रूप से हुक क्या करता है, एनीमेशन को चालू और बंद करना है, और बाद में onतदनुसार अद्यतन करें । इसलिए हम एनीमेशन की स्थिति को सटीक रूप से प्राप्त कर सकते हैं। ऐसा करने के बिना एक तदर्थ पर जवाब होगा duration

/**
 * A hook to provide animation status.
 * @class useAnimate
 * @param {object} _                props
 * @param {async} _.animate         Promise to perform animation
 * @param {object} _.node           Dom node to animate
 * @param {bool} _.disabled         Disable animation
 * @returns {useAnimateObject}      Animate status object
 * @example
 *   const { on, onToggle } = useAnimate({
 *    animate: async () => { },
 *    node: node
 *  })
 */

import { useState, useCallback } from 'react'

const useAnimate = ({
  animate, node, disabled,
}) => {
  const [on, setOn] = useState(false)

  const onToggle = useCallback(v => {
    if (disabled) return
    if (v) setOn(true)
    animate({ node, on: v }).finally(() => {
      if (!v) setOn(false)
    })
  }, [animate, node, disabled, effect])

  return [on, onToggle]
}

export default useAnimate

उपयोग निम्नलिखित है,

  const ref = useRef()
  const [on, onToggle] = useAnimate({
    animate: animateFunc,
    node: ref.current,
    disabled
  })
  const onClick = () => { onToggle(!on) }

  return (
      <div ref={ref}>
          {on && <YOUROWNCOMPONENT onClick={onClick} /> }
      </div>
  )

और चेतन कार्यान्वयन हो सकता है,

import anime from 'animejs'

const animateFunc = (params) => {
  const { node, on } = params
  const height = on ? 233 : 0
  return new Promise(resolve => {
    anime({
      targets: node,
      height,
      complete: () => { resolve() }
    }).play()
  })
}

0

आप उसके लिए React SyntheticEvent का उपयोग कर सकते हैं ।

तरह की घटनाओं के साथ onAnimationEnd या onTransitionEnd आपको लगता है कि पूरा कर सकते हैं।

रिएक्ट डॉक्स: https://reactjs.org/docs/events.html#animation-events

कोड उदाहरण: https://dev.to/michalczaplinski/super-easy-react-mount-unmount-animations-with-hooks-4foj

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.