Nếu bạn xây dựng một ứng dụng React thì tại bất kỳ thời điểm nào trong khi lập trình, chắc chắn bạn đã gặp những lỗi khó hiểu và không cung cấp bất kỳ thông tin nào có ý nghĩa về những gì đang thực sự xảy ra.
Điều này có thể có nghĩa rằng lỗi xảy ra ở đoạn nào đấy trong ứng dụng, React Component đã không xử lý lỗi một cách tốt đẹp, cũng chủ yếu bởi vì nó không phải là nghiệp vụ liên quan đến ứng dụng đang phát triển.
Giới thiệu Error Boundaries
Lỗi Javascript trong một phần của UI không nên ảnh hưởng toàn bộ ứng dụng. Để giải quyết vấn đề này cho người dùng React, React 16 giới thiệu một khái niệm mới gọi là “Error Boundary”
Error Boundary là một component trong React giúp bắt các lỗi trong component con của nó và làm vài điều có ý nghĩa với chúng như là đăng chúng lên một service ghi lại lỗi hoặc hiển thị một fallback UI để xác định component con nào bị lỗi trong khi vẫn duy trì ứng dụng hoạt động bình thường.
Do đó, đối với các khối chức năng được bảo đảm với Error Boundaries, nó phải là con của một trong những vị trí đầu tiên.
Trước khi chúng ta bắt đầu ví dụ làm thế nào để sử dụng nó trong React 16, hãy chú ý rằng Error Boundaries không bắt được lỗi trong trường hợp sau:
- Event handlers. – Sử dụng đoạn
try/catch
thay thế bên trong event handler. - Asynchronous code
- Server Side Render
- Các lỗi trong Error Boundaries. Bạn sẽ không thể bảo vệ người khác nếu bạn không thể bảo vệ được chính mình
componentDidCatch()
Phương thức Lifecycle là các hàm đặc biệt được gọi tại các state khác nhau trong vòng đời của một component. Những state này có thể được phân loại thành Mounting, Updating, Unmounting và error handling.
Đối với một component được coi là một Error Boundary, nó phải tạo sử dụng phương thức lifecycle componentDidCatch()
để xử lý các lỗi. Nó hoạt động giống như try/catch
của Javascript dùng.
Phương thức componentDidCatch
được gọi với các tham số error
và info
chứa nhiều thông tin hơn về lỗi xảy ra.
Nơi sử dụng chúng
Giống như chi tiết của các Component React hoàn toàn phụ thuộc vào bạn, Error Boundaries có thể được xác định như mong muốn của bạn. Bạn có thể có một Error Boundary cấp cao nhất để ngăn chặn việc ứng dụng bị sự cố do xuất hiện các lỗi không mong muốn và hiển thị các thông báo thích hợp hơn.
Đối với bài viết này, chúng ta sẽ tạo một Error Boundary chỉ bao phủ một chức năng cụ thể với các lỗi của chúng ta thiết kế
Tạo Error Boundary
Để bắt đầu, chúng ta sẽ tạo một Component đơn giản chỉ cho phép bạn nhập vào tối đa 5 ký tự trong một input. Trường hợp nhập nhiều hơn, chúng ta sẽ làm gián đoạn internet.
class FiveMax extends React.Component { constructor(props) { super(props); this.state = { value: ''} this.handleChange = this.handleChange.bind(this); } handleChange(e) { this.setState({ value: e.target.value}) } render() { if(this.state.value.length > 5) { throw new Error('You cannot enter more than five characters!'); } return ( <div> <label>Type away: </label> <input type="text" value={this.state.value} onChange={this.handleChange} /> </div> ); } } ReactDOM.render(<FiveMax />, document.getElementById('root'));
Nếu bạn nhập vào nhiều hơn 5 ký tự, bạn nên nhận được một lỗi loè sáng lớn trong console của bạn
Bạn cũng để ý rằng, text box bạn nhập cũng biến mất do lỗi này. OK rồi! Chúng ta sẽ tạo một Error Boundary. Tên là Shield
.
class Shield extends React.Component { constructor(props) { super(props); // Add some default error states this.state = { error: false, info: null, }; } componentDidCatch(error, info) { // Something happened to one of my children. // Add error to state this.setState({ error: error, info: info, }); } render() { if(this.state.error) { // Some error was thrown. Let's display something helpful to the user return ( <div> <h5>Sorry. More than five characters!</h5> <details style={{ whiteSpace: 'pre-wrap' }}> {this.state.info.componentStack} </details> </div> ); } // No errors were thrown. As you were. return this.props.children; } }
Không có gì đặc biệt phải không. Cái mới duy nhất chúng ta có trong component này mà chắc chắn bạn chưa từng sử dụng trước đây đó là phương thức componentDidCatch
Khi một lỗi xảy ra trong bất kỳ component con nào của nó, error của state sẽ được cập nhập và lỗi có ý nghĩa được hiển thị. Nếu không thì Shield
sẽ tiếp tục và hiển thị các component con bình thường.
Thực thi Error Boundary
Để bắt đầu sử dụng Error Boundary, chúng ta sẽ cùng nhìn 2 kịch bản riêng biệt sau
Kịch bản 1: 2 Component ở trong cùng một Error Boundary
Trong tình huống bạn có 2 component ở trong cùng một Error Boundary và khi có lỗi xảy ra 1 trong 2 component này, cả 2 đều ảnh hưởng đến cấu trúc của phương thức render trong Shield
Component.
Để thử trường hợp này, chúng ta sẽ thêm 2 FiveMax
component bên trong Shield
Error Boundary
// Shield Component // FiveMax Component function App() { return ( <div> <h3>Two children under one error boundary. If one crashes. Both are affected!</h3> <Shield> <FiveMax /> <FiveMax /> </Shield> </div> ); } ReactDOM.render(<App />, document.getElementById('root'));
Khi bạn nhập nhiều hơn 5 ký tự vào trong bất kỳ 1 trong 2 text box, một lỗi được hiển thị trên console và chúng ta có được điều mong muốn và nhiều thông tin hơn được hiển thị cho người dùng thay cho cả 2 component
Tất cả đều tốt nhưng chúng ta không cần thiết bị mất component còn lại mà không có bất kỳ lỗi nào xảy ra với nó. Nào chúng ta hày cũng sửa nó
Kịch bản 2: 2 component, mỗi thành phần có Error Boundary riêng
Nào để ngăn chặn những gì đã xảy ra trong kịch bản 1, chúng ta sẽ có từng FiveMax
component bên trong Shield
Error Boundary của riêng nó.
// Shield Component // FiveMax Component function App() { return ( <div> <h3>Two children, each with their own Error Boundary. One crashes, the other is not affected</h3> <Shield><FiveMax /></Shield> <Shield><FiveMax /></Shield> </div> ); } ReactDOM.render(<App />, document.getElementById('root'));
Tiếp theo thử nhập nhiều hơn 5 ký tự trong bất kỳ component nào. Cần chú ý điều gì không? Thay vì mất cả 2 component khi lỗi xảy ra, bạn sẽ chỉ mất component bị ảnh hưởng. Phần còn lại của ứng dụng còn nguyên vẹn