在 React with SCSS 中添加 div 淡出和 div 的条件渲染

Add div fade-out in React with SCSS and conditional rendering of div

我目前使用 SCSS/SASS mixinkeyframes.

在 React 中成功淡入有条件渲染的 div

我还想在 div 关闭后添加淡出功能。我尝试动态更改 div (className={div_enable?"div_in":"div_out"}) 的 class,但问题是,将条件渲染更改为 false/关闭 div 的事件](在我下面的示例中,当 div 处于焦点时按 Enter)是将其 class 更改为 div_out 的相同操作。条件渲染首先被触发,因此 div 在可以应用淡出 div_out class 之前完全消失。

如何在 div 关闭时添加淡出功能的同时保留 div 的条件渲染逻辑?

Update:我发现了 using OnAnimationEnd 的可能性,我认为这是最容易实现的,无需大修我的代码。但是,我不确定如何将教程的功能组件代码转换为我项目的 Class 组件代码。

我也发现了using ReactCSSTransitionGroup的可能性。链接的教程使用了一个 React Class 组件,我正在慢慢地尝试去除它并将其转录到我下面的代码中。但是,恐怕将 ReactCSSTransitionGroup 实施到我的实际项目中(此处未显示)将需要进行大修,因此我更愿意使用 OnAnimationEnd 之类的东西。

CodePen with working SCSS/fade-in

class MyForm extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
    this.state = { div_enable: false };
  }
  submitForm = (event) => {
    event.preventDefault();
    this.setState({ div_enable: true }, () => this.myRef.current.focus());
  };
  closeModal = () => {
    if (event.key === "Enter" && event.shiftKey === false) {
      this.setState({ div_enable: false });
    }
  };

  render() {
    const { div_enable } = this.state;
    return (
      <div content>
        <form onSubmit={this.submitForm}>
          <input
            id="text_entry"
            type="text"
            placeholder="Enter text"
          />
          <input type="submit" />
        </form>
        {div_enable && (
          <div
            className={div_enable?"div_in":"div_out"}
            onKeyDown={this.closeModal}
            tabIndex={0}
            ref={this.myRef}
          >
            <p>Press Enter to make me disappear.{" "}
            </p>
          </div>
        )}
      </div>
    );
  }
}

ReactDOM.render(<MyForm />, document.getElementById("root"));
@mixin fade-in {
  opacity: 1;
  animation-name: fadeInOpacity;
  animation-iteration-count: 1;
  animation-timing-function: ease-in;
  animation-duration: 0.2s;
}

@mixin fade-out {
  opacity: 0;
  animation-name: fadeInOpacity;
  animation-iteration-count: 1;
  animation-timing-function: ease-in;
  animation-duration: 0.2s;
}

@keyframes fadeInOpacity {
  0% {
      opacity: 0;
  }
  100% {
      opacity: 1;
  }
}

.div_in {
  @include fade-in;
  border: 1px solid;
  background: lightblue;
}

.div_out {
  @include fade-out;
  border: 1px solid;
  background: lightblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>

如果您想为条件渲染元素启用 CSS 退出动画,您可以完全删除 SCSS 并转换条件渲染声明(例如,{my_condition && ... } ) 到 <CSSTransition> tags--while making sure to include the unmountOnExit prop within the tags (which prop is inherited from CSSTransition's parent component, Transition)--像这样:

:

// Javascript
{div_enable &&
 <div className={div_enable?"div_in":"div_out"}>
     <p>My paragraph</p>
 </div>
 }
// CSS
/* [See original question] */

新:

// Javascript
{
 <CSSTransition
 in={div_enable}
 timeout={200}
 classNames="fade"
 unmountOnExit
 >
     <div className="div_in">
         <p>My paragraph</p>
     </div>
 </CSSTransition>
}
// CSS
.div_in {
  border: 1px solid;
  background: lightblue;
}
.fade-enter {
  opacity: 0;
}
.fade-enter-active {
  opacity: 1;
  transition: opacity 200ms;
}
.fade-exit {
  opacity: 1;
}
.fade-exit-active {
  opacity: 0;
  transition: opacity 200ms;
}

完整代码(我无法让 importing ES6 modules ({CSSTransition}) in Whosebug's editor 工作,所以下面的 Whosebug 代码没有 运行):

Working CodePen Example

import {CSSTransition} from "https://cdnjs.cloudflare.com/ajax/libs/react-transition-group/4.4.1/react-transition-group.min.js";

class MyForm extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
    this.state = {
      text_exists_enable: false,
      text_empty_enable: false,
      text_field: "",
    };
  }

  textEntered = (event) => {
    this.setState({ text_field: event.target.value });
    console.log(event.target.value);
  };

  submitForm = (event) => {
    event.preventDefault();
    if (this.state.text_field !== "") {
      this.setState(
        {
          text_exists_enable: true,
        },
        () => this.myRef.current.focus()
      );
    } else {
      this.setState(
        {
          text_empty_enable: true,
        },
        () => this.myRef.current.focus()
      );
    }
  };

  closeBlueBox = () => {
    if (event.key === "Enter" && event.shiftKey === false) {
      this.setState({
        text_exists_enable: false,
        text_empty_enable: false,
      });
    }
  };

  render() {
    const { text_exists_enable, text_empty_enable } = this.state;
    return (
      <div content>
        <form onSubmit={this.submitForm}>
          <input
            type="text"
            placeholder="Enter text"
            onChange={this.textEntered}
          />
          <input type="submit" />
        </form>
        {
          <CSSTransition
            in={text_exists_enable}
            timeout={200}
            classNames="fade"
            unmountOnExit
          >
            <div
              className="div_in"
              onKeyDown={this.closeBlueBox}
              tabIndex={0}
              ref={this.myRef}
            >
              <p> Textbox HAS text! </p>
            </div>
          </CSSTransition>
        }
        {
          <CSSTransition
            in={text_empty_enable}
            timeout={200}
            classNames="fade"
            unmountOnExit
          >
            <div
              className="div_in"
              onKeyDown={this.closeBlueBox}
              tabIndex={0}
              ref={this.myRef}
            >
              <p> Textbox is EMPTY! </p>
            </div>
          </CSSTransition>
        }
      </div>
    );
  }
}

ReactDOM.render(<MyForm />, document.getElementById("root"));
.div_in {
  border: 1px solid;
  background: lightblue;
}

.fade-enter {
  opacity: 0;
}
.fade-enter-active {
  opacity: 1;
  transition: opacity 200ms;
}
.fade-exit {
  opacity: 1;
}
.fade-exit-active {
  opacity: 0;
  transition: opacity 200ms;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-transition-group/4.4.1/react-transition-group.min.js"></script>
<div id="root"></div>