ReactJS and Functional Programming

Functional Programming

Functional Programming là gì?

Tôi luôn băn khoăn tự hỏi thế nào là một source code lý tưởng dưới con mặt lập trình viên, code thực hiện được nhiều chức năng vừa ngắn lại vừa dễ hiểu, chỉ mới nhìn đã muốn lưu lại để dùng dần ?

Chúng ta có thể viết code dài bao nhiêu tùy thích, thực hiện bao nhiêu chức năng tùy ý nhưng kèm theo đó là yêu cầu về độ phức tạp vẫn phải trong tầm kiểm soát thì không hề dễ chút nào.

Một điều chắc chắn rằng developer giỏi cỡ Bill Gate đi nữa nhưng chỉ cần nhìn vào một chút lộn xộn (trong code) như dưới đây thôi cũng đủ gây hoang mang rồi.

messy_wires.jpg

Vì lẽ đó, một trong những mong muốn hàng đầu của bất kỳ lập trình viên nào là giữ code đơn giản nhất có thể. So sánh với việc viết một công thức nấu ăn, bạn có thể dễ dàng đi vào từng chi tiết và có thể chia sẻ kinh nghiệm rửa cà chua sạch như nào hay ngâm đỗ thế nào là vừa. Công thức của bạn tiếp tục với các chi tiết và những điều nhỏ nhặt đó cho đến khi dài như một câu chuyện cổ tích mà bạn không bao giờ muốn đọc lại. Nên thay vào đó hãy giả định là người đọc có những kiến thức cơ bản về nấu ăn như sơ chế hay chuẩn bị nguyên liệu và bạn có thể tập trung miêu tả những bước khác quan trọng hơn như nướng bánh trong bao lâu với nhiệt độ ra sao. Bạn có thể cùng đưa ra được một công thức nhưng ở cách ngắn gọn hơn, rõ ràng hơn và hấp dẫn với người đọc hơn. Thực tế đó dù ít dù nhiều lại được biết đến dưới cái tên trừu tượng hóa trong lập trình.

Xem xét một ví dụ đơn giản về việc in tất cả các phần tử trong mảng ra màn hình

function printArray(arr){
    for (i=0; i < arr.length, i++){
        print(arr[i]);
    }
}

Chúng ta có thực sự cần biết index của các phần tử trong mảng ? Sẽ ra sao nếu chúng ta muốn làm thêm việc gì đó với các phần tử trên? Viết thêm một hàm tương tự với vòng lặp for ? Hay có thể truyền "làm gì đó" như là một tham số của hàm, làm nó trở nên "trừu tượng" hơn

function forEach(arr, action){
    for (ele in arr){
        action(ele);
    }
}
//Then we can call like that
forEach([1,2,3], function(e){
    //do some thing with e
});

Bạn có thấy nó gần giống với hàm Array.map trong Ruby ko?

Functional Programming với ReactJs

Rất ít người sẽ nghĩ đến việc viết hàm theo cách thứ hai ở ví dụ trên cho đến khi những file JS lên tới hàng nghìn dòng với hàng trăm những vòng lặp for tương tự nhau. Hơn nữa, môi trường Javascipt tiêu chuẩn chỉ cung cấp vài hàm thiết yếu, khi cần một cái gì đó cao cấp hơn mức nhu yếu phẩm lập trình viên phải tự viết ra,hoặc một cách nhàn hạ hơn, sử dụng lại code của người khác.

Có lẽ vì quá chán viết đi viết lại một số hàm cơ bản tỷ như generate DOM hay event handler cũng như để tiện cho việc dùng lại code đã viết của người khác nên Facebook tạo ra ReactJs mà nhờ nó một ngày nào đó khi viết web app chúng ta không cần sử dụng code HTML nữa (hucau)

Hãy cùng ngó qua ấn tượng đầu tiên về cách mà họ tạo ra nút (like) với virtual DOM được ca ngợi thần thánh và kỳ diệu như thế nào

var LikeButton = React.createClass({
    getInitialState: function(){
        return {liked: false};
    },
    handleClick: function(){
        this.setState({state: !this.state.liked});
    },
    render: function(){
        var text = this.state.liked ? 'like' : 'unlike';
        return (
            <p onClick={this.handleClick}>
                You {text} this. Click to toggle
            </p>
        );
    }
})
//usage
React.render(
  <LikeButton />,
  document.getElementById('example')
);

Một cách khái quát React nói không với:

  • controllers
  • directives
  • templates
  • global event listener
  • models
  • view models

đơn giản chỉ là components, và vì là components tính reusable được đẩy lên cao nhất có thể write once, use every where.

Thử tưởng tượng khi bạn sử dụng raw manipulation để làm việc tương tự. Code bị lặp lại khá nhiều, rời rạc và khó quản lý, mỗi khi bạn muốn nút like xuất hiện ở đâu đó bạn lại phải viết lại đoạn code dưới đây:

var like_button = document.createElement("p");
var liked = false;
var text = liked ? 'like' : 'unlike';
like_button.innerHTML = "You " + text + " this. Click to toggle";
like_button.onclick = function(){
    liked = !liked;
    text = liked ? 'like' : 'unlike';
    this.innerHTML = "You " + text + " this. Click to toggle";
}

document.getElementById('example').appendChild(like_button);

Trong một nỗ lực áp dụng tâm pháp trừu tượng hóa để khiến code trong sáng hơn, chúng ta có một version na ná React như dưới đây

//just kidding
var Rereact = {
    render: function(component, ancestor){
        ancestor.appendChild((new component).obj());
    }
};

var LikeButton = function(){
    this.liked = false;
    this.text = function(){
        var action = this.liked ? 'like' : 'unlike';
        return "You " + action + " this. Click to toggle";
    };
    this.obj = function(){
        var that = this;
        var btn = document.createElement("p");
        btn.innerHTML = this.text();
        btn.onclick = function(){
            that.liked = !that.liked;
            this.innerHTML = that.text();
        };
        return btn;
    }
}

//usage
Rereact.render(LikeButton, document.getElementById('example'));

TL;DR

Không thể nói rằng React là library tốt nhất để bắt đầu functional programming với Javascript mà theo tôi bạn nên thử implement mọi thứ với native JS trước. Rồi sau đó hay cũng xem React cung cấp cho bạn những gì để rút ngắn functions declare cũng như giảm bớt đi khối lượng những công việc nhàm chán lặp đi lặp lại khi phát triển UI. Nếu bạn dự định phát triển web application theo hướng full component/API thì React đang nổi lên là một sự lựa chọn sáng suốt, cho những người yêu thích sự nhanh gọn mà vẫn đầy mạnh mẽ.

Tài liệu