Quản lý React state bằng React Easy State

Overview

Trong qúa trình phát triển các application trên nền tảng React JS, tôi đã tìm hiểu về React Easy State, trong bài viết này tôi sẽ giới thiệu về nó.
Easy State là 1 thư viện để quản lý React state, về cơ bản nó không hoàn toàn có 1 triết lý cụ thể, cũng giống như lập trình hướng function, nó chủ yếu hướng đến sự đơn giản trong việc sử dụng React. Bạn có thể lưu lại state trong những đối tượng đơn giản, sử dụng và thay đổi giá trị theo bất cứ cách nào mà bạn muốn. Đằng sau các trạng thái được lưu trữ và bao bọc bởi ES6 Proxies, những trạng thái này đã bị chặn tất cả những hành động cơ bản như get, set. Chúng đăng ký phần nào trong đó được lưu trữ, phần nào được sử dụng và render thành phần cũng như tự động tái render khi cần thiết.
Điều thú vị về Proxy là sự minh bạch. Bạn chỉ cần phải xử lý với các đối tượng đơn giản và các thành phần React và cho phép Easy State giữ chúng đồng bộ.

Cách sử dụng

Thành phần trong library

Easy State có 2 luật sau:

  • Luôn bọc các thành phần lại bằng view
  • Luôn bọc các trạng thái chứa các đối tượng bằng store

Cách cài đặt

npm install react-easy-state

Ngoài ra Easy State hỗ trợ Create React App bạn có thể cài đặt 1 project nhanh chóng bằng cách:

npx create-react-app my-app
cd my-app
npm install react-easy-state
npm start

Cách dùng

  1. Tạo 1 store từ những đối tượng được truyền vào. store không khác gì những đối tượng JS thông thường
import { store } from 'react-easy-state';

const user = store({
  name: 'Thi'
});

// stores behave like normal JS objects
user.name = 'Hung';
  1. Tạo reactive views bọc lại bằng view. Một reactive views được render khi mà các property của store được thay đổi
import React, { Component } from 'react';
import { view, store } from 'react-easy-state';

const user = store({ name: 'Bob' });

class HelloComp extends Component {
  onChange = ev => (user.name = ev.target.value);

  // the render is triggered whenever user.name changes
  render() {
    return (
      <div>
        <input value={user.name} onChange={this.onChange} />
        <div>Hello {user.name}!</div>
      </div>
    );
  }
}

// the component must be wrapped with `view`
export default view(HelloComp);

Thực hành

Chúng ta sẽ bắt đầu thực hành với 1 ví dụ đơn giản, đó là tạo 1 đồng hồ để đếm thời gian. Gồm chức năng đơn giản: start, stop
Đầu tiên chúng ta cần tạo ra 1 cái đồng hồ để lưu trữ các trạng thái. Nó lưu lại số lần nó đếm và nó có thể được start và stop. Đơn giản như sau:

import { store } from 'react-easy-state'

const clock = store({
  ticks: 0,
  start () {
    clock.intervalId = setInterval(() => clock.ticks++, 10)
  },
  stop () {
    clock.intervalId = clearInterval(clock.intervalId)
  }
})

export default clock

Sau đó chúng ta cần tạo view để hiển thị đồng hồ. Sử dụng cách đơn giản nhất, xây dựng 1 hàm thành phần như sau:

import React from 'react'
import { view } from 'react-easy-state'
import clock from './clock'

function StopWatch () {
  const { ticks, start, stop } = clock

  return (
    <div>
      <div>{ticks}</div>
      <button onClick={start}>Start</button>
      <button onClick={stop}>Stop</button>
    </div>
  )
}

export default view(StopWatch)

Thêm 1 chút css và chạy demo chúng ta sẽ được 1 kết quả với các chức start stop như sau:
demo1
Làm thêm 1 chút nâng cao nữa bằng cách thêm format cho đồng hồ theo đơn vị phút, giây, tích tắc, và thêm tính năng reset được. Add thêm thư viện hỗ trợ moment để hiển thị thời gian theo format.

import { store } from 'react-easy-state'
import moment from 'moment'

// use 'clock' instead of 'this' in the store methods to make them passable as callbacks
const clock = store({
  ticks: 0,
  start () {
    clock.intervalId = setInterval(() => clock.ticks++, 10)
  },
  stop () {
    clock.intervalId = clearInterval(clock.intervalId)
  },
  get time () {
    const time = moment(0).millisecond(clock.ticks * 10)

    return {
      seconds: time.format('mm:ss'),
      fraction: time.format('SS')
    }
  },
  get isTicking () {
    return clock.intervalId !== undefined
  },
  toggle () {
    clock.isTicking ? clock.stop() : clock.start()
  },
  reset () {
    clock.ticks = 0
    clock.stop()
  }
})

export default clock

Phần view được thay đổi thành như sau:

import React from 'react'
import { view } from 'react-easy-state'
import clock from './clock'

function StopWatch () {
  const { time, toggle, reset, isTicking } = clock
  const label = isTicking ? 'Stop' : 'Start'

  return (
    <div>
      <div>
        {time.seconds}
        <small>{time.fraction}</small>
      </div>
      <button onClick={toggle}>{label}</button>
      <button onClick={reset}>Reset</button>
    </div>
  )
}

export default view(StopWatch)

Bạn đã có 1 demo hoàn chỉnh về đồng hồ đếm giờ:
demo2

Phân tích

Chúng ta đã hiểu phần nào cách sử dụng của Easy State qua ví dụ. Vậy về cơ bản thì Easy State bí mật theo dõi 2 điều:

  • store truy theo từng function get, set mỗi thuộc tính của từng state
  • view truy theo hàm render đang được chạy

Khi một thuộc tính của store được sử dụng bên trong một thành phần render, nó được ghép nối render này và được lưu trong một list. Sau đó - khi cùng một thuộc tính bị thay đổi - nó tìm kiếm tất cả các hàm render được lưu và thực thi chúng. Bằng cách này, view luôn được giữ đồng bộ với state.
Hãy phân tích ví dụ đồng hồ bấm giờ trên. Khi đồng hồ này được render lần đầu tiên, view coi như đồng hồ đang được hiển thị. Đồng hồ này dùng các thuộc tính time, isTicking, intervalId để render. Tất cả những hoạt động này đều được chặn bởi ProxyEasy State sẽ lưu lại rằng đồng hồ sử dụng các thuộc tính này.
Sau đó người dùng ấn start, 1 vòng lặp được khởi tạo kèm theo intervalId được set giá trị. Hành động set này được bắt bời Proxy cái mà nhận ra rằng thuộc tính: intervalIdisTicking bị thay đổi, Easy State sẽ render mọi thành phần mà giựa trên những thay đổi này
Vòng lặp thời gian này được đếm mỗi 10 mili giây. Easy State hiểu là đồng hồ đã đếm 1 lần và sẽ render lại các thành phần mỗi lần đếm.

Vậy tại sao chúng ta nên dùng

Easy State dựa trên một ý tưởng cũ - được gọi là lập trình reactive trong suốt - từng được sử dụng bởi VueJS và MobX. Sự đổi mới nằm trong việc thực hiện, không phải là khái niệm.
Cả MobX và VueJS đều sử dụng getters và bộ định tuyến ES5 để theo dõi quyền truy cập và đột biến thuộc tính trên các cửa hàng. Cách tiếp cận này có những hạn chế.
Bằng cách sử dụng ES6 Proxies, Easy State cuối cùng có thể hoàn thành tính reactive trong suốt. Nó có thể theo dõi bất cứ điều gì từ các thuộc tính động để xóa các hoạt động, các thuộc tính kế thừa, các phép lặp, đếm và truy cập thuộc tính.
Việc sử dụng sẽ giúp cho việc quản lý các state trong lập trình React được rõ ràng đơn giản hơn.

Nguồn tham khảo: https://github.com/solkimicreb/react-easy-state, https://blog.risingstack.com/introducing-react-easy-state/

All Rights Reserved