TL;DR: Thay vì dùng component Query
của apollo-client, sử dụng ApolloConsumer
và truy cập trực tiếp đến client
qua render prop giúp chúng ta viết một component AutoComplete
ngắn gọn và dễ đọc hơn
1. Tạo AutoComplete để tìm kiếm và hiển thị người dùng
Gần đây mình muốn xây dựng tính năng tìm kiếm người dùng trong một dự án. Khi người dùng nhập vào ô Input
, danh sách gợi ý sẽ hiển thị. Dữ liệu người dùng được lấy từ endpoint GraphQL (Node.js) bằng Apollo Client. Ban đầu hơi khó, nhưng cách mình dùng cuối cùng như sau .

2. So sánh giữa Query
và ApolloConsumer
Trước tiên, trong phương thức render()
bên trong lớp React.Component
của tôi, tôi sử dụng ApolloConsumer
thay vì Query
component từ thư viện react-apollo
. Tài liệu hướng dẫn có nói rằng nên ưu tiên sử dụng Query
, nhưng trong trường hợp của tôi thì điều đó lại không đúng. Hãy xem đoạn mã sau:
render() {
const { dataSource, value } = this.state;
return (
<ApolloConsumer>
{client => (
<div>
<AutoComplete
onSelect={this.onSelect}
onSearch={value => {
this.handleSearch({ value, client });
}}
placeholder=”Enter Opponent Name”
value={value}
>
{dataSource.map((user, index) => {
return (
<AutoComplete.Option key={index}>
{user.name}
</AutoComplete.Option>
);
})}
</AutoComplete>
</div>
)}
</ApolloConsumer>
);
}
Chúng ta thêm component AutoComplete
, component này sẽ kích hoạt hàm được chỉ định trong onSearch
mỗi khi giá trị nhập vào thay đổi. Đồng thời, chúng ta đặt giá trị (value
) của nó dựa trên state
của component. Sau đó, chúng ta render từng người dùng gợi ý hiện có trong mảng dataSource
từ state
.
Nếu chúng ta sử dụng Query
component thay cho cách thiết lập này, có thể chúng ta sẽ muốn cập nhật state
mỗi khi nhận được phản hồi từ server. Nhưng: Việc cập nhật state
bên trong render()
là không hoạt động.
Có thể có một cách khác, đó là truyền dữ liệu trực tiếp vào prop dataSource
của AutoComplete
thông qua data
được cung cấp bởi render prop
của Query
. Tuy nhiên, theo quan điểm của tôi, cách tiếp cận ở trên có vẻ dễ đọc và dễ bảo trì hơn. Giờ hãy cùng tìm hiểu sâu hơn vào bên trong phương thức handleSearch
.
3. Cách xử lý truy vấn
Như đã thấy ở trên, chúng ta truyền một đối tượng chứa client
và value
làm đối số cho phương thức handleSearch
. Dưới đây là hình thức của nó:
handleSearch = async ({ value, client }) => {
this.setState({
value
});
if (value.length > 1) {
const { data } = await client.query({
query: USERS_QUERY,
variables: { query: value, boardId: this.props.boardId }
});
this.setState({
dataSource: data ? data.users : []
});
}
};
Trước hết, chúng ta muốn cập nhật giá trị trong state
để phản ánh đầu vào của người dùng. Bằng cách này, nội dung nhập vào sẽ được hiển thị trong component AutoComplete
.
Tiếp theo, chúng ta truy vấn dữ liệu từ client
và định nghĩa giá trị vừa nhập (cùng với boardId
, một giá trị cụ thể trong ví dụ của tôi) làm biến truy vấn cho USERS_QUERY
.
Bằng cách sử dụng async/await, chúng ta cập nhật dataSource
trong state
để phản ánh danh sách người dùng mới được tìm thấy. Tôi bọc các câu lệnh này trong một câu điều kiện if
để chỉ truy vấn dữ liệu khi người dùng nhập ít nhất 2 ký tự, nhằm giảm lưu lượng và tải cho backend.
4. Tổng kết
Còn nhiều việc khác, ví dụ xử lý khi người dùng chọn một item trong danh sách gợi ý, nhưng chúng phụ thuộc mạnh vào từng dự án nên tác giả không đi sâu. Hy vọng bài viết ngắn này đã giúp bạn, hẹn gặp lại lần sau!
Tham khảo thêm: