HOC nghe khá trừu tượng và cao siêu, một cái tên sang chảnh cho một cách làm trong React, nó cũng có cái hạn chế và ưu điểm riêng, tuy nhiên thích thì học thôi.
Ôn lại Currying function
Để đọc hiểu bài này dĩ nhiên cần nắm cơ bản ES6, hiểu cà-ri function là thế nào (Currying Functional Programming)
Cà-ri function là cách viết tách một function nhận một đốn...ggggg arguments, tách function đó ra thành nhiều function con, mỗi function nhận 1 argument. Ví dụ
// một hàm sum thông thường
const sum = (a, b) => a + b;
// cà-ri function
const curriedSum = function(a) {
return function(b) {
return (a + b)
}
}
// viết hàm cà-ri bằng arrow function
const curriedSum = a => b => a + b
//gọi hàm cà-ri
curriedSum(4)(5)
Một số cách viết khác của ES6 tìm lại mấy bài cũ của mình đã chia sẻ.
Higher-Order Function
Cái này không mới, trước đây trong javascript vẫn thường viết kiểu truyền một callback function (vì trong javascript function được xem là object nên làm được chuyện này), hay 1 function trả về một kết quả trả về của function khác.
const calculator = (inputFunction) => (...args) => {
const resultValue = inputFunction(...args);
console.log(resultValue);
return resultValue;
}
const add = (...all) => {
return all.reduce((a, b) => a + b, 0);
}
const multiply = (...all) => {
return all.reduce((a,b) => a*b, 1)
}
Ta có thể sử dụng hàm calculator
như sau
calculator(mutiply)(2,4);
// => 8
calculator(add)(3,6,9,12,15,18);
// => 63
Các hàm như add
, multiply
chấp nhận số lượng input không giới hạn, hàm calculator
sử dụng như một container, làm cha thiên hạ, sai hết đứa này tới đưa khác làm việc, extend thêm một số xử lý trước khi gọi hàm add
, multiply
Higher-Order Component
Một higher-order component là một một function nhận vào một component
như một argument và trả về "phiên bản mở rộng" của component đó.
(InputComponent) => {
return ExtendedComponent
}
// hoặc
InputComponent => ExtendedComponent
ExtendedComponent
là một component container, nó trả về InputComponent
với một số extend
const withGreyBg = WrappedComponent => class NewComponent extends Component {
const bgStyle = {
backgroundColor: 'grey',
}
render() {
return (
<div className='wrapper' style={bgStyle}>
<WrappedComponent {...this.props} />
</div>
)
}
}
const SmallCardWithGreyBg = withGreyBg(SmallCard);
const BigCardWithGreyBg = withGreyBg(BigCard);
const HugeCardWithGreyBg = withGreyBg(HugeCard);
class CardsDemo extends Component {
render() {
<SmallCardWithGreyBg {...this.props} />
<BigCardWithGreyBg {...this.props} />
<HugeCardWithGreyBg {...this.props />
}
}
Nhược điểm
- Trong một số trường hợp sẽ làm ảnh hưởng đến hiệu năng, đến mức Andrew Clark phải build hẳn một thư viện để giải quyết vấn đề này
- Rõ ràng sẽ thấy HOC ko minh bạch trong việc đã extend những phần nào cho thằng con
- Nếu một component được bọc trong nhiều HOC cùng lúc, có thể sẽ vô tình dẫm đạp qua lại
- Debug cũng không dễ gì vì đang sử dụng arrow function, phải tung thêm chiêu
displayName
Initializing...