+11

HỌC REACTJS THÔNG QUA VÍ DỤ PHẦN 3

1. Mở đầu.

xin chào các bạn, trong phần 2 mình và các bạn chúng ta đã cùng nhau hoàn thiện những phần tiếp của todo app. Trong phần trước chúng ta đã hoàn thiện:

  • Tạo mock data.
  • Thêm gói uuid để tạo id phân biệt cho các item.
  • Render Item tại App.
  • In gía trị của các Item. Các bạn có thể tham khảo các bài viết trước ở đây.

PHẦN 2. PHẦN 1. và trong bài viết này chúng ta sẽ xoá item với 1 popup thông báo - bằng cách tìm hiểu thêm 1 gói đã hỗ trợ sẵn là react-bootstrap-sweetalert. Nào chúng ta cùng bắt đầu nào.

2. Delete Item.

Luồng xử lí của chúng ta ở bài này là khi người dùng click vào nút Delete sẽ hiện ra một popup thông báo xóa sản phẩm cùng với tên sản phẩm đó, khi nhấn vào xác nhận thì mới xóa, còn không thì thôi.

Bước 1: Tìm hiểu và sử dụng package SweetAlert.

Về phần demo của SweetAlert các bạn có thể xem tại https://sweetalert.js.org/. Chúng ta sẽ sử dụng SweetAlert dành cho ReactJS các bạn có thể xem tại https://github.com/chentsulin/sweetalert-react. Để thêm package chúng ta gõ vào cmd như sau: npm install sweetalert-react --save Sau khi thêm package và chạy lại ứng dụng của mình, mở file App.js và import nó vào: import SweetAlert from 'sweetalert-react'; Việc ẩn hay hiện popup alert sẽ dựa vào một state kiểu boolean khai báo trong App.js mặc định là false vì ban đầu nó chưa hiện ra.

constructor(props) {    
    super(props);
    this.state = {
        items: Items,
        showAlert: false
    }
}

Chúng ta test thử xem package có hoạt động ngon nghẻ không trước đã. Viết đoạn JSX này vào phần return của hàm render.

render() {
    return (
        <div className="container">
            <button onClick={()=>this.setState({ showAlert: true })}>Alert</button>
            <SweetAlert
                show={this.state.showAlert}
                title="Demo"
                text="SweetAlert in React"
                onConfirm={()=>this.setState({ showAlert: false })}
            />
            <Title />
            ...
        </div>
    );
}

Nếu click thử vào button mà hiện ra Alert là gần ngon rồi chỉ thiếu mỗi css nữa thôi. Theo tác giả: You should import sweetalert.css from cdn, file, node_modules(sweetalert/dist/sweetalert.css) or wherever can find the css code. Sau một hồi mò mẫm thì chúng ta đã import được css của nó import './../node_modules/sweetalert/dist/sweetalert.css';

Bước 2: Xây dựng các hành động ẩn popup SweetAlert.

Sau khi đã import được SweerAlert và cả css của nó thành công, chúng ta tập trung vào các hành động để ẩn popup này. Có 3 hành động chính để ẩn popup:

  1. Click vào nút Cancel.
  2. Nhấn ESC trên bàn phím. 3.Click vào vùng bên ngoài của popup để ẩn. Sau khi tìm kiếm trên github của họ chúng ta sửa lại đoạn SweetAlert như sau:
<SweetAlert
    show={this.state.showAlert}
    title="Demo"
    text="SweetAlert in React"
    showCancelButton
    onOutsideClick={()  => this.setState({ showAlert: false })}
    onEscapeKey={()     => this.setState({ showAlert: false })}
    onCancel={()        => this.setState({ showAlert: false })}
    onConfirm={()       => this.setState({ showAlert: false })}
/>

Bước 3: Lấy tên của sản phẩm muốn xóa.

Trong popup Alert chúng ta sẽ phải để tên sản phẩm cần xóa vào đó chứ không ghi một đoạn text là "SweetAlert in React" cố định như ở trên. Trong file App.js ta sẽ tạo ra một state kiểu string để lưu tên sản phẩm muốn xóa và gắn state này vào trong SweetAlert đồng thời sửa luôn title SweetAlert cho hợp lí.

constructor(props) {    
    super(props);
    this.state = {
        ...
        titleAlert: ''
    }
}
....
<SweetAlert
    show={this.state.showAlert}
    title="Delete Item"
    text={this.state.titleAlert}
    showCancelButton
    onOutsideClick={()  => this.setState({ showAlert: false })}
    onEscapeKey={()     => this.setState({ showAlert: false })}
    onCancel={()        => this.setState({ showAlert: false })}
    onConfirm={()       => this.setState({ showAlert: false })}
/>

Trong file App.js chúng ta viết hàm handleShowAlert với tham số nhận vào là item.

handleShowAlert = (item) => {
    console.log(item);
}

Tiếp tục ta gắn hàm này vào làm props của Component Item.

renderItem = () => {
    let {items} = this.state;
    return mapld(items,(item,index) => {
        return (
            <Item 
                ...
                handleShowAlert={this.handleShowAlert}
            />
        )
    });
}

Trong file Item.js ta viết sự kiện onClick cho nút Delete và truyền toàn bộ đối tượng Item vào làm tham số.

<button 
    type="button" className="btn btn-danger btn-sm"
    onClick={()=>this.props.handleShowAlert(item)}
>
    Delete
</button>

Vậy là khi click vào button Delete ta đã truyền được toàn bộ thông tin Item muốn xóa sang cho file App.js. Trong App.js hàm handleShowAlert có nhiệm vụ bật popup lên và truyền tên sản phẩm muốn xóa vào popup đó.

handleShowAlert = (item) => {
    this.setState({
        showAlert: true,
        titleAlert: item.name
    });
}

Bước 4 : Lấy id của sản phẩm muốn xóa.

Qua các bước trên khi click vào Delete ở sản phẩm nào thì hiện lên một popup với tên của sản phẩm đó. Để xử lí việc xóa sản phẩm chúng ta cần phải biết id của sản phẩm. Trong các thông tin được gửi sang App.js đã bao gồm cả id giờ ta chỉ việc tạo một state lưu giá trị đó.

class App extends Component {
    constructor(props) {    
        super(props);
        this.state = {
            ...
            titleAlert: '',
            idAlert: ''
        }
    }
    ...
    handleShowAlert = (item) => {
        this.setState({
            showAlert: true,
            titleAlert: item.name,
            idAlert: item.id
        });
    }
}

Bước 5 : Xóa sản phẩm.

Chúng ta chỉ xóa sản phẩm khi popup hiện lên và người dùng bấm OK để xác nhận. Trong sự kiện onConfirm của Component SweetAlert ta sẽ gọi đến một hàm để xử lí xác nhận.

<SweetAlert
    ...
    onConfirm={() => this.handleDeleteItem()}
/>

Trong hàm handleDeleteItem ta phải lấy state chứa id muốn xóa và state chứa mảng các sp ban đầu .

handleDeleteItem = () => {
    let {idAlert, items} = this.state;
}

Check độ dài mảng items lớn hơn 0. - Dùng hàm for để duyệt mảng items, ta so sánh id từng phần tử có giống với id muốn xóa không. Nếu giống thì xóa đi.

handleDeleteItem = () => {
    let {idAlert, items} = this.state;
    if(items.length > 0) {
        for(let i = 0; i < items.length; i++) {
            if(items[i].id === idAlert) {
                items.splice(i, 1);
                break;
            }
        }
    }
}

Việc cuối cùng chúng ta cần làm là khi xóa xong sản phẩm thì ẩn cái popup đi bằng cách thay đổi giá trị state showAlert thành false.

handleDeleteItem = () => {
    let {idAlert, items} = this.state;
    if(items.length > 0) {
        ...
    }
    this.setState({
        showAlert: false
    });
}

Ở phần trên nếu các bạn kĩ lưỡng có thể khi xóa sản phẩm xong thì set lại các giá trị idAlert và titleAlert về ban đầu, nói chung tùy các bạn.

Bước 6 : Hiển thị thông báo khi không còn sản phẩm.

Khi chúng ta xóa hết các sản phẩm thì nên hiển thị ra ngoài một câu thông báo cho người dùng biết. Trong file App.js hàm renderItem ta thêm một câu lệnh điều kiện kiểm tra độ dài của mảng.

renderItem = () => {
    let {items} = this.state;
    if(items.length === 0) {
        return <Item item={0} />
    }
    return mapld(items,(item,index) => {
        ...
    });
}

Trong file Item.js hàm render ta kiểm tra điều kiện và trả về một kiểu hiển thị riêng.

render() {
    let {item,index} = this.props;
    if(item === 0) {
        return (
            <tr>
                <td colSpan="4" className="text-center">  
                    <h4>No Item</h4>
                </td>
            </tr>
        )
    }
    let classNameLabel = '';
    ... 
}

3 . Tạm Kết.

Bài viết cũng đã khá dài, mình xin kết thúc bài viết tại đây, hẹn gặp lại các bạn trong các phần về sau này.


All rights reserved

Bình luận

Đăng nhập để bình luận
Avatar
@hungvux
thg 5 17, 2019 1:33 SA

sao lại phải gọi super(props); trong constructor đấy a :v

Avatar
@KhoaNguyen
thg 5 17, 2019 1:38 SA

1.Khi làm việc với React thì khi viết constructor mà không có super() thì sẽ lỗi. Không viết super(props) thì sẽ không thể dùng được this.props trong constructor.

2.Tại sao phải gọi super() trong Javascript super như là "hàm khởi tạo của class cha" (parent class constructor). Có nghĩa là bạn không thể dùng this cho đến khi gọi super().

3.Không truyền props vào super thì sẽ ra sao Sẽ ra sao khi bạn truyền tham số props vào super(). Khi không gọi super(props) thì bạn sẽ không thể dùng this.props bên trong constructor Mình xin trả lời bạn như vậy, cảm ơn bạn đã quan tâm đến bài viết của mình, nếu có thắc mắc bạn vui lòng để lại comment nhé

Avatar
@hungvux
thg 5 17, 2019 1:43 SA

ok ak 👍👍👍

Avatar
@TruongDQ
thg 6 12, 2020 1:03 CH
Avatar
@TruongDQ
thg 6 12, 2020 3:11 CH

cho e hỏi chỗ bước 3. chỗ gắn hàm này vào làm props của Component Item. sao lại là mapId ạ...e tìm mọi chỗ k có cái nào như thế ạ

Avatar
@tinhbeng
thg 6 23, 2020 9:46 SA

Nó là cái loop items: return items.map((item,index) => { return( <Item ..... /> ) })

Avatar
@huytran187
thg 11 18, 2020 8:23 SA

Sao ở bước 3 mình viết sự kiện onClick cho nút Delete và truyền toàn bộ đối tượng Item vào làm tham số. Khi click vào nút Delete thì nó lại xuất hiện lỗi TypeError: this.props.handleShowAlert is not a function

Avatar
@Linnnnnnn
thg 2 26, 2021 1:08 SA

rồi bạn làm đc chưa ạ

Avatar
@jbergloda1
thg 5 25, 2021 9:22 SA

mình cũng bị lỗi này

Avatar
@supert
thg 8 7, 2021 5:52 SA

Đúng ra bước 3 tất cả các code phải đặt trong component ListItem, nếu đặt trong App thì phải tạo props cho ListItem, theo mình nghĩ vậy

Avatar
@thienan97
thg 6 1, 2021 9:54 SA

Mình thì bị lỗi import hoài ko đc file css của Sweetalert, ai biết sửa xin chỉ giáo ạ.

Avatar
@buiquan
thg 8 12, 2021 9:37 SA

bạn import theo cách này trong file index.js nhé:

import './../node_modules/sweetalert/dist/sweetalert.css';

Avatar
@buiquan
thg 8 12, 2021 7:05 SA

bạn ko rạch ròi việc xử lý thêm SweetAlert ở Component nào, khiến mọi người hơi khó hiểu 😦

Avatar
@buiquan
thg 8 12, 2021 9:36 SA

về bản chất, <SweetAlert> sẽ đặt ở Component ListItem thì dễ xử lý và sẽ dễ hiểu hơn button Delete bên phía component Item chỉ cần gọi onClick sang phía ListItem là ok:

<button type="button" className="btn btn-danger btn-sm" onClick={()=>this.props.handleShowAlert(itemArg)}> Delete </button>

bên phía ListItem sẽ xử lý hết: handleShowAlert(), handleDeleteItem()

Avatar
+11
Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí