【问题标题】:How to trigger animation using react-transition-group如何使用 react-transition-group 触发动画
【发布时间】:2019-06-21 18:05:05
【问题描述】:

问题是我有一个具有三种状态的表单:错误、信息和成功。根据服务器的响应正在使用上述状态触发烤面包机,我需要在服务器响应可用时添加淡入淡出动画。

toasterService.js

 import React, {useState} from 'react';
 import {Transition} from 'react-transition-group';
 import './toasterService.css'

 export default function ToasterService(content, timeout, style) {
const inProp = useState(true); // always call hook on top level
const duration = timeout;
const transitionStyles = {
    entering: {opacity: 1},
    entered: {opacity: 1},
    exiting: {opacity: 0},
    exited: {opacity: 0},
};

let defaultStyle = {};

switch (style) {
    case 'info' :
        defaultStyle = {
            transition: `opacity ${duration}ms ease-in-out`,
            opacity: 0,
            backgroundColor: '#00c5dc',
            color: '#ffffff'
        };
        break;

    case 'success' :
        defaultStyle = {
            transition: `opacity ${duration}ms ease-in-out`,
            opacity: 0,
            backgroundColor: '#8ebe4b',
            color: '#ffffff'
        };
        break;
    case 'danger' :
        defaultStyle = {
            transition: `opacity ${duration}ms ease-in-out`,
            opacity: 0,
            backgroundColor: '#FF0000',
            color: '#ffffff'
        };
        break;
    default :
}


return (<div className="main-alert">

        <Transition in={inProp} timeout={duration}>
            {state => (
                <div style={{
                    ...defaultStyle,
                    ...transitionStyles[state]
                }}>
                    {content}
                </div>
            )}
        </Transition>
    </div>

);
}

登录.js

import ToastService from '../../services/core/toasterService';
// on click of login btn
  socialSignIn = () => {
    let obj = {};
    obj = this.state;

    fetch(url,
        {
            method: 'post',
            body: JSON.stringify(obj)

        }).then(function (res) {
        console.log(res.json());
          ToastService('success', 5000,'info');
        return res.json();

    })
};

Toast 服务接收 3 个参数,但烤面包机没有出现。我错过了什么?

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    我最近自己构建了一个 Toastr 组件,基本功能使用 styled-components、animejs 和 react-transition-group,这可能会帮助您正确完成它。

    注意:我认为使用animejs 比为过渡的每个阶段设置样式更容易。您基本上可以获得进入或退出元素的参考,并使用 animejs 为它设置动画。

    react-transition-group 将为您提供对这些道具中元素的引用:

    <Transition
      key={item.id}
      onEntering={animateEnter}  // animateEnter will have a reference to the element
      onExiting={animateExit} // animateExist will have a reference to the element
      timeout={{
        enter: 500,
        exit: 500
      }}
      unmountOnExit={true} // I was testing, but I don't think this prop is necessary in my component
    >
    

    See working example on CodeSandbox

    这是代码:

    index.js

    import React from "react";
    import ReactDOM from "react-dom";
    import Toastr from "./Toastr";
    import SomeComponent from "./SomeComponent";
    
    import "./styles.css";
    
    function App() {
      return (
        <Toastr>
          <SomeComponent />
        </Toastr>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    

    Toastr.js

    import React, { useRef, useEffect, useState } from "react";
    import styled from "styled-components";
    import { TransitionGroup, Transition } from "react-transition-group";
    import anime from "animejs";
    import ToastrContext from "./ToastrContext";
    
    // CREATE A USE TOASTER HOOK ?
    // MAYBE CREATE AN APP STATE TO STORE THE TOASTS
    
    const S = {};
    
    S.FixedContainer = styled.div`
      position: fixed;
      bottom: 10px;
      /* right: 5px; */
      /* left: 0; right: 0; */
      /* CENTER IT HORIZONTALLY */
      left: 50%;
      transform: translateX(-50%);
    `;
    
    S.ToastContainer = styled.div`
      width: 300px;
      height: 64px;
      margin-top: 10px;
      margin-bottom: 10px;
      /* padding-left: 10px; */
      color: white;
      font-weight: bold;
      background: #39c16c;
      border-radius: 5px;
      display: flex;
      align-items: center;
      justify-content: center;
    `;
    
    function Toastr(props) {
      const lastToastLengthRef = useRef(0);
      const [toasts, setToasts] = useState([]);
      const toastID = useRef(0);
    
      console.log("Toastr rendering...");
      console.log(toasts);
    
      function addNewToast(toast) {
        setToasts(prevState => {
          const aux = Array.from(prevState);
          aux.push({ msg: toast, id: toastID.current });
          toastID.current = toastID.current + 1;
          return aux;
        });
      }
    
      useEffect(() => {
        if (toasts.length > lastToastLengthRef.current) {
          console.log("useEffect: Toast was added...");
          // TOAST WAS ADDED
          setTimeout(() => {
            setToasts(prevState => {
              const aux = Array.from(prevState);
              aux.shift();
              return aux;
            });
          }, 1000);
          lastToastLengthRef.current = toasts.length;
          return;
        }
        lastToastLengthRef.current = toasts.length;
      }, [toasts]);
    
      function animateEnter(element) {
        anime({
          targets: element,
          opacity: 0,
          duration: 0
        });
        anime({
          targets: element,
          opacity: 1,
          easing: "easeOutExpo",
          duration: 2000
        });
      }
    
      function animateExit(element) {
        anime({
          targets: element,
          opacity: 0,
          easing: "easeOutExpo",
          duration: 2000
        });
      }
    
      // const toastItems = toasts.map((item,index) =>
      //   <S.ToastContainer key={item.id}>{item.msg}</S.ToastContainer>
      // );
    
      const toastItems = toasts.map((item, index) => (
        <Transition
          key={item.id}
          onEntering={animateEnter}
          onExiting={animateExit}
          timeout={{
            enter: 500,
            exit: 500
          }}
          unmountOnExit={true}
        >
          <S.ToastContainer>{item.msg}</S.ToastContainer>
        </Transition>
      ));
    
      return (
        <React.Fragment>
          <S.FixedContainer>
            <TransitionGroup component={null}>{toastItems}</TransitionGroup>
            {/* {toastItems} */}
          </S.FixedContainer>
          <ToastrContext.Provider value={addNewToast}>
            {props.children}
          </ToastrContext.Provider>
        </React.Fragment>
      );
    }
    
    // Toastr.whyDidYouRender = true;
    
    export default Toastr;
    

    ToastrContext.js

    import React from "react";
    
    const ToastrContext = React.createContext(null);
    
    export default ToastrContext;
    

    SomeComponent.js(会发出 toast)

    import React, { useContext } from "react";
    import ToastrContext from "./ToastrContext";
    import styled from "styled-components";
    
    function SomeComponent() {
      const sendToast = useContext(ToastrContext);
    
      return (
        <React.Fragment>
          <div>Hey! Click for some toasts!</div>
          <button onClick={() => sendToast("This is your toast!")}>Click</button>
        </React.Fragment>
      );
    }
    
    export default SomeComponent;
    

    【讨论】:

      猜你喜欢
      • 2020-06-07
      • 2021-05-06
      • 2019-01-17
      • 2020-07-03
      • 2019-01-27
      • 1970-01-01
      • 1970-01-01
      • 2018-04-03
      • 2019-07-07
      相关资源
      最近更新 更多