Học ReactJS Full Đầy Đủ Nhất

Bài 16: ReactJS - Animation

I- Giới thiệu về Animation :

  • Để xử lý các animation, ta có thể lựa chọn cách viết truyền thống là css modules, viết css thuần, sau đó viết logic xử lý vài sự kiện bằng event. Tuy nhiên, ta nên thử lựa chọn 1 số thư viện, nó giúp việc quản lý animation bằng mã js dễ quản lý hơn. Trong đó 1 thư viện có thể giúp điều đó là Reacts-spring.
  • Nó là 1 thư viện xử lý các hoạt hình, lấy cảm hứng từ animated và react-motion, xử lý các hoạt hình hầu như hay xảy ra với UI như việc hoạt động xử lý vật lý của con lắc lò xo khi lắc( khối lượng, độ căng của dây lò xo, ma sát với không khí). Bởi vì nó rất nhẹ ( 10.7KB với bản trên web, 9.7kb với bản trên native. Với khả năng xử lý linh động và được support từ các ông lớn như airbnb hay matterapp, thì việc được cộng đồng ủng hộ nhiệt tình từ khi nó mới ra mắt, còn chần chờ gì nữa mà không tìm hiểu nó nào.

II-  Cài đặt Animation :

Cài đặt lệnh sau :
npm install react-spring

III- API và các đối tượng hay sử dụng :

1. CÁC COMMON API:

Đây là các api để config mà tất cả các spring(hook/component) đều sử dụng. Ta sử dụng chúng để config để có hoạt hình hợp lý, chia làm các nhóm sau(mình chỉnh liệt kê một số config cảm thấy hay dùng và có thể hiểu, vì nó rất nhiều).
Configs:
  • duration: thời gian hiệu ứng(giá trị mặc định là undefined)
  • precision: độ chính xác
  • tension: độ căng, giá trị này càng lớn hoạt hình càng diễn ra liên tục
  • friction: ma sát, giá trị càng lớn dẫn đến sức cản của hoạt hình càng cao, hoạt hình diễn ra chậm hơn
  • mass: khối lượng
Presets:
Đây là bộ giá trị của mass, tension và friction. Mặc định của nó là : config.default tương ứng với { mass: 1, tension: 170, friction: 26 }. Các bộ khác các bạn có thể coi trong docs của nó.
Properties:
Các thuộc tính hay dùng sẽ là:
  • from: (từ) cũng giống như from trong keyframe
  • to(đến):cũng giống như to trong keyframe
  • delay: tạm dừng mili giây trước khi bắt đầu
  • config: sử dụng các config đã nêu ở mục config trên
  • reset: set bằng true nếu muốn reset lại mỗi khi kết thúc 1 lần hoạt hình.
  • onStart: ở giai đoạn bắt đầu sẽ làm gì
  • onReset: ở giai đoạn đứng yên sẽ làm gì
    Interpolations: mình thấy các api hay dùng là map, output với extrapolate.
    Tham khảo tại đây: https://www.react-spring.io/docs/hooks/api

2.  Công cụ hỗ trợ (UNIT):

  • Màu sắc(names, rgb, rgba, hsl, hsla, gradients)
  • Đơn vị(cm, mm, in, px, pt, pc)
  • Relative lengths (em, ex, ch, rem, vw, vh, vmin, vmax, %)
  • Góc đo(deg, rad, grad, turn)
  • Flex and grid units (fr, etc)
  • All HTML attributes
  • SVG paths
  • Arrays
  • String patterns (transform, border, boxShadow, etc)
  • Non-animatable string values (visibility, pointerEvents, etc)
  • ScrollTop/scrollLeft

3.  Một số Hook Api xử lý animaiton hay dùng:

React-spring có 5 hook hay dùng(viết hook, nên nó được dùng như custom hook). Mình sẽ giới thiệu 1 số ví dụ cơ bản và 1 số ví dụ hay dùng của nó. Các hook sẽ dùng với các api common đã được giới thiệu trước đó.
a. Use Spring:
Được dùng với đơn hoạt hình, để di chuyển (giống như from -> to giống keyframe trong css).
Một số ví dụ:
  • Ví dụ khi ta muốn hiệu ứng từ từ hiện ra đoạn text
Ví dụ này tương đương:
from  {
opacity: 0;
}
to {
opacity: 1;
}
Phân tích ví dụ:
  • Ta sử dụng useString như một hook, và chắc chắn có truyền vào from và tham số khác và opacity , nó sẽ trả về props styles tương ứng (ngoài ra còn có set để set lại trạng thái style cho hoạt hình nếu muốn thay đổi khi có event xảy ra hay stop nếu muốn stop hoạt hình).
  • animation.h1 → render ra thẻ h1 + props là styles được truyền vào → animation tương ứng
  • Ví dụ về hiệu scroll:
Lần này ta ta truyền vào thay vì param opacity , ta truyền vào scroll . Hiệu ứng này có kết quả như sau:
  • Ví dụ hiệu ứng vẽ svg:
Lần này ta thêm config delay và duration để có thể xem hiệu ứng từ từ( config là 1 hỗ trợ thêm từ react-spring nếu ta muốn hiển thị theo nhiều cách khác nhau)
b) useSprings:
Tương tự như với useSpring, tuy nhiên được áp dụng với 1 list các đối tượng mà ta muốn nó có hiệu ứng gần như giống nhau.
c) useTrail:
Nếu bạn muốn xử lý 1 mảng các phần tử, bạn muốn các phần tử trong mảng này sẽ có hiệu ứng lần lượt được thực hiện từ phần tử thứ nhất đến phần tử cuối cùng. Hiệu ứng này sẽ tạo ra hiệu ứng liên tiếp nhau, ví dụ như thế này:
d) useTransition:
Nếu bạn muốn quản lý sự biến đổi của các hiệu ứng khác nhau:
Ngoài các api common, nó còn còn sử dụng các api khác như from, enter , update, leave,vv để quản lý các trạng thái khi đến, rời đi hay hủy bỏ.
Ví dụ mình thấy hay nhất trong docs của nó liên quan đến chuyển trang khi kết hợp react-router:
e)useChain:
xử dụng kết hợp với useRef để xác định đối tượng và xác định thứ tự thực hiện các animation.
Như ví dụ này:

4.  Lưu ý:

Ngoài ra, trước đây react-spring viết thành các component xử lý animation có chức năng tương tự: Spring tương ứng với useSpring, Transition tương ứng với useTransition, Trail tương ứng với useTrail.
Nhưng giờ đa phần họ dùng với hook, các ví dụ về component trên github cũng đã đã bị xóa đi và đều chuyển sang dùng với hook.

IV- Ví dụ :

Bước 1 : Cài đặt React CSS Transitions Group :
Ta cài đặt bằng dòng lệnh sau :
npm install react-addons-css-transition-group
Bước 2 : Thêm file CSS :
Ta tạo file style.css như sau :
css/style.css
Để có thể  sử dụng được file này trong App, ta cần phải liên kết nó với index.html như sau :
<!DOCTYPE html>
<html lang = "en">
   <head>
      <link rel = "stylesheet" type = "text/css" href = "./style.css">
      <meta charset = "UTF-8">
      <title>React App</title>
   </head>
   <body>
      <div id = "app"></div>
      <script src = 'index_bundle.js'></script>
   </body>
</html>
Bước 3 : Sửu dụng animation :
Ta sẽ tạo một component React. Phần tử ReactCSSTransitionGroup sẽ được sử dụng để bao bọc component mà ta muốn animate cho nó. Nó sẽ sử dụng 2 hàm là transitionAppear và transitionAppearTimeout, khi transitionEnter và transitionLeave  không đung
App.jsx
import React from 'react';
var ReactCSSTransitionGroup = require('react-addons-css-transition-group');

class App extends React.Component {
   render() {
      return (
         <div>
            <ReactCSSTransitionGroup transitionName = "example"
               transitionAppear = {true} transitionAppearTimeout = {500}
               transitionEnter = {false} transitionLeave = {false}>
					
               <h1>My Element...</h1>
            </ReactCSSTransitionGroup>
         </div>      
      );
   }
}
export default App;
main.js
import React from 'react'
import ReactDOM from 'react-dom';
import App from './App.jsx';

ReactDOM.render(<App />, document.getElementById('app'));
Animation trong CSS khá đơn giản như sau :
css/style.css
.example-appear {
   opacity: 0.04;
}
.example-appear.example-appear-active {
   opacity: 2;
   transition: opacity 50s ease-in;
}
 Kết qủa khi chạy ứng dụng như hình dưới đây 
Bước 4 : Enter và Leave trong animations :
Enter và leave animaitons được sử dụng khi ta muốn thêm hoặc xoá phần tử trong list
app.jsx
import React from 'react';
var ReactCSSTransitionGroup = require('react-addons-css-transition-group');

class App extends React.Component {
   constructor(props) {
      super(props);
		
      this.state = {
         items: ['Item 1...', 'Item 2...', 'Item 3...', 'Item 4...']
      }
      this.handleAdd = this.handleAdd.bind(this);
   };
   handleAdd() {
      var newItems = this.state.items.concat([prompt('Create New Item')]);
      this.setState({items: newItems});
   }
   handleRemove(i) {
      var newItems = this.state.items.slice();
      newItems.splice(i, 1);
      this.setState({items: newItems});
   }
   render() {
      var items = this.state.items.map(function(item, i) {
         return (
            <div key = {item} onClick = {this.handleRemove.bind(this, i)}>
               {item}
            </div>
         );
      }.bind(this));
      
      return (
         <div>      
            <button onClick = {this.handleAdd}>Add Item</button>
				
            <ReactCSSTransitionGroup transitionName = "example" 
               transitionEnterTimeout = {500} transitionLeaveTimeout = {500}>
               {items}
            </ReactCSSTransitionGroup>
         </div>
      );
   }
}
export default App;
main.js
import React from 'react'
import ReactDOM from 'react-dom';
import App from './App.jsx';

ReactDOM.render(<App />, document.getElementById('app'));
css/style.css
.example-enter {
   opacity: 0.04;
}
.example-enter.example-enter-active {
   opacity: 5;
   transition: opacity 50s ease-in;
}
.example-leave {
   opacity: 1;
}
.example-leave.example-leave-active {
   opacity: 0.04;
   transition: opacity 50s ease-in;
}
Kết qủa như sau :

V- Tổng kết :

Việc sử dụng react-spring rất linh hoạt, giúp việc kiểm soát animation bằng js , nó giúp kiểm soát khi nào bắt đầu , khi nào kết thúc hay hủy bỏ hiệu ứng một cách chủ động hơn.
Ngược lại, nó có thể nặng hơn so với việc sử dụng css thuần(nhưng chỉ áp dụng cho web, và 1 số platform rất hạn chế).
Do đó, việc sử dụng animation như thế nào còn tùy thuộc mức độ của dự án, cũng như mục đích hướng tới của nó là như thế nào.