openplanning

Ví dụ React-Transition-Group Transition (NodeJS)

  1. Mục tiêu của bài học
  2. Tạo project và cài đặt thư viện
  3. Ví dụ Transition đơn giản
  4. Ví dụ Transition (unmountOnExit)

1. Mục tiêu của bài học

Thư viện react-transition-group cung cấp cho bạn các thành phần để bạn tạo ra các hiệu ứng hoạt hình trong ứng dụng React. Bài viết dưới đây giới thiệu chi tiết về thư viện này, các thành phần mà nó cung cấp, các API,..
Trong bài học này tôi hướng dẫn bạn thực hành một vài ví dụ với các thành phần Transition & TransitionGroup được cung cấp bởi thư viện react-transition-group.
Một thành phần khác tương tự là CSSTransition giúp bạn làm việc dễ dàng hơn với CSS transition:

2. Tạo project và cài đặt thư viện

Tạo một dự án React với tên transition-app bằng cách thực hiện các lệnh dưới đây:
# Install 'create-react-app' tool (If it has never been installed)

npm install -g create-react-app

# Create project with 'create-react-app' tool:

create-react-app transition-app
Cài đặt thư viện react-transition-group:
# CD to your project

cd transition-app

# Install 'react-transition-group':

npm install react-transition-group --save
Chạy ứng dụng của bạn:
# Run app:

npm start

3. Ví dụ Transition đơn giản

Dưới đây là hình ảnh xem trước của ví dụ này:
  • Khi giá trị của 'in' thay đổi từ false thành true, Thành phần <Transition> sẽ chuyển sang trạng thái 'entering', và giữ yên trong trạng thái này 'timout' mili giây, sau đó nó chuyển sang trạng thái 'entered'.
  • Khi giá trị của 'in' thay đổi từ true thành false, Thành phần <Transition> sẽ chuyển sang trạng thái 'exiting', và giữ yên trong trạng thái này 'timout' mili giây, sau đó nó chuyển sang trạng thái 'exited'.
OK, Trở lại với project trên. Xóa hết nội dung của các tập tin App.js & App.css:
App.css
.my-msg {
   color: blue;
}

.my-msg-entering {
    color: blue;
    font-size: 150%;
    transition-duration: 1s;
 }

 .my-msg-entered {
    font-size: 150%;
    color: red;
 }

.my-msg-exiting {
    font-size: 100%;
    color: black;
    transition-duration: 1s;
}

.my-highlight  {
  color: red;
}
App.js
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";

import {
  TransitionGroup,
  CSSTransition,
  Transition
} from "react-transition-group";

class App extends React.Component {
  render() {
    return (
      <div>
        <MyComponent />
      </div>
    );
  }
}

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      stateOfIn: false,
      message: ""
    };
  }

  // Begin Enter: Do something here!
  onEnterHandler() {
    console.log("Begin Enter");
    this.setState({ message: "Begin Enter..." });
  }

  onEnteringHandler() {
    console.log("Entering... (Wait timeout!)");
    this.setState({ message: "Entering... (Wait timeout!)" });
  }

  onEnteredHandler() {
    console.log("OK Entered!");
    this.setState({ message: "OK Entered!" });
  }

  // Begin Exit: Do something here!
  onExitHandler() {
    console.log("Begin Exit");
    this.setState({ message: "Begin Exit..." });
  }

  onExitingHandler() {
    console.log("Exiting... (Wait timeout!)");
    this.setState({ message: "Exiting... (Wait timeout!)" });
  }

  onExitedHandler() {
    console.log("OK Exited!");
    this.setState({ message: "OK Exited!" });
  }

  render() {
    return (
      <div>
        <h3>&lt;Transition in={"{this.state.stateOfIn}"} &gt;</h3>

        <b>{"\u2728"} Focus on Textfield and see the effects:</b>
        <ul>
          <li className="my-highlight">
            Now 'in' = {String(this.state.stateOfIn)}
          </li>
          <li> false --&gt; true (Enter)</li>
          <li> true --&gt; false (Exit)</li>
        </ul>
        <div className="my-highlight">{this.state.message}</div>

        <br />

        <input
          type="text"
          onFocus={() => {
            this.setState({ stateOfIn: true });
          }}
          onBlur={() => {
            this.setState({ stateOfIn: false });
          }}
        />
        <br />

        <Transition
          in={this.state.stateOfIn}

          timeout={{ enter: 1500, exit: 2500 }}
          onEnter={() => this.onEnterHandler()}
          onEntering={() => this.onEnteringHandler()}
          onEntered={() => this.onEnteredHandler()}
          onExit={() => this.onExitHandler()}
          onExiting={() => this.onExitingHandler()}
          onExited={() => this.onExitedHandler()}
        >
        {(statusName) => (
           <div className={`my-msg my-msg-${statusName}`} >User name 2-20 characters</div>
        )}
        </Transition>
      </div>
    );
  }
}

export default App;
Không cần thay đổi nội dung của các tập tin index.js & index.html:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();
index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="theme-color" content="#000000">
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
    <title>React CssTransition</title>
  </head>
  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
  </body>
</html>
Ví dụ 2:
Cũng với ví dụ ở trên, chúng ta thay đổi nội dung của App.css giống dưới đây để có một hiệu ứng phức tạp hơn:
App.css (Edited) (2)
.my-msg {
   color: blue;
   margin-left: 300px;
   opacity: 0;
}

 .my-msg-entering {
    color: blue;
    margin-left: 0px;
    opacity: 1;
    font-size: 150%;
    transition-duration: 1s;
 }

 .my-msg-entered {
    opacity: 1;
    margin-left: 0px;
    font-size: 150%;
    color: red;
 }

.my-msg-exiting {
    opacity: 0;
    font-size: 100%;
    margin-left: 300px;
    color: black;
    transition-duration: 1s;
}

.my-highlight  {
  color: red;
}

4. Ví dụ Transition (unmountOnExit)

<ReactTransitionGroup.Transition  unmountOnExit = {true/false} mountOnEnter = {true/false}>

    <!-- Child Component -->
    <MySingleElement>
       <MyOtherElements />
    </MySingleElement>

</ReactTransitionGroup.Transition>
Hình ảnh xem trước của ví dụ này:
App3.css
.my-msg-entering {
    color: blue;
 }

 .my-msg-entered {
    color: red;
 }

.my-highlight  {
  color: red;
}
App3.js
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App3.css";

import {
  TransitionGroup,
  CSSTransition,
  Transition
} from "react-transition-group";

class App extends React.Component {
  render() {
    return (
      <div>
        <MyComponent />
      </div>
    );
  }
}

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      stateOfIn: false,
      message: ""
    };
  }

  // Begin Enter: Do anything!
  onEnterHandler() {
    console.log("Begin Enter");
    this.setState({ message: "Begin Enter..." });
  }

  onEnteringHandler() {
    console.log("Entering... (Wait timeout!)");
    this.setState({ message: "Entering... (Wait timeout!)" });
  }

  onEnteredHandler() {
    console.log("OK Entered!");
    this.setState({ message: "OK Entered!" });
  }

  // Begin Exit: Do anything!
  onExitHandler() {
    console.log("Begin Exit");
    this.setState({ message: "Begin Exit..." });
  }

  onExitingHandler() {
    console.log("Exiting... (Wait timeout!)");
    this.setState({ message: "Exiting... (Wait timeout!)" });
  }

  onExitedHandler() {
    console.log("OK Exited!");
    this.setState({ message: "OK Exited!" });
  }

  render() {
    return (
      <div>
        <h3>&lt;Transition in={"{this.state.stateOfIn}"} &gt;</h3>

        <b>{"\u2728"} Click the buttons and see the effects:</b>
        <ul>
          <li className="my-highlight">
            Now 'in' = {String(this.state.stateOfIn)}
          </li>
          <li> false --&gt; true (Enter)</li>
          <li> true --&gt; false (Exit)</li>
        </ul>
        <div className="my-highlight">{this.state.message}</div>

        <br />

        <input
          type="text"
          onFocus={() => {
            this.setState({ stateOfIn: true });
          }}
          onBlur={() => {
            this.setState({ stateOfIn: false });
          }}
        />
        <br />

        <Transition
          in={this.state.stateOfIn}

          unmountOnExit

          timeout={{ enter: 1500, exit: 2500 }}
          onEnter={() => this.onEnterHandler()}
          onEntering={() => this.onEnteringHandler()}
          onEntered={() => this.onEnteredHandler()}
          onExit={() => this.onExitHandler()}
          onExiting={() => this.onExitingHandler()}
          onExited={() => this.onExitedHandler()}
        >
          {stateName => {
            // stateName: 'entering', 'enterd', 'exiting', 'exited'
            switch (stateName) {

              case "entering":
                return (
                  <b className="my-msg-entering">
                    ⭐ Note: User name 2-20 characters
                  </b>
                );
              case "entered":
                return (
                  <b className="my-msg-entered">
                    ⭐ Note: User name 2-20 characters
                  </b>
                );
              case "exiting":
                return <div>(User Name)</div>;
              case "exited":
                return <b>(User Name)</b>;
              default:
                return <div>??</div>;
            }
          }}
        </Transition>
      </div>
    );
  }
}

export default App;
Thay đổi nội dung tập tin index.js:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

import App from './App3'; // IMPORTANT!
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));

serviceWorker.unregister();