tencent cloud

即时通信 IM

Search Store

Download
聚焦模式
字号
最后更新时间: 2026-07-02 17:13:34
SearchStore 提供了基于云端搜索的搜索能力。如果自定义组件能力不能支持您的业务,可以使用 SearchStore 实现您的需求。

属性

属性名
类型
说明
userList
UserProfile[]
用户搜索结果列表。
userTotalCount
number
用户搜索结果总数。
hasMoreUsers
boolean
用户搜索结果是否还有下一页。
groupList
GroupSearchInfo[]
群组搜索结果列表。
groupTotalCount
number
群组搜索结果总数。
hasMoreGroups
boolean
群组搜索结果是否还有下一页。
groupMemberList
Record<string, GroupMember[]>
群成员搜索结果,按 groupID 分组。
groupMemberTotalCount
number
群成员搜索结果总数。
hasMoreGroupMembers
boolean
群成员搜索结果是否还有下一页。
messageResults
MessageSearchResultItem[]
消息搜索结果列表。每项按会话聚合,包含会话 ID、会话展示信息、命中消息数量和消息列表。
messageResultTotalCount
number
消息搜索结果总数。
hasMoreMessageResults
boolean
消息搜索结果是否还有下一页。

方法

方法名
类型
说明
search
(keywordList: string[], option?: SearchOption) => Promise<void>
发起搜索。默认会同时搜索用户、群组、群成员和消息;可通过 option.searchScope 限制搜索范围。调用时会重置当前结果和分页游标。
searchMore
(searchType: SearchType) => Promise<void>
加载指定搜索类型的下一页结果。searchType 可为 User、Group、GroupMember、Message。
destroy
() => void
销毁当前 SearchStore 实例,清理订阅和状态。通常由 React/Vue3 封装层自动管理。
SearchOption
字段名
类型
说明
keywordListMatchMode
KeywordListMatchMode
多关键词匹配模式:Or 或 And。默认 Or。
searchScope
SearchType[]
搜索范围。默认包含用户、群组、群成员、消息四类。
pageSize
number
每页数量,默认 20。
userFilter
UserSearchFilter
用户搜索过滤条件。
messageFilter
MessageSearchFilter
消息搜索过滤条件。
groupMemberFilter
GroupMemberSearchFilter
群成员搜索过滤条件。

使用示例

该使用示例展示了如何使用 SearchStore 实现一个简单的云端搜索用户的组件代码。
index.tsx
index.css
import { useState } from 'react';
import {
SearchType,
SearchStore,
} from '@tencentcloud/chat-uikit-react';
import './styles.css';

function SearchStoreBasicDemo() {
const {
hasMoreUsers,
search,
searchMore,
userList,
userTotalCount,
} = SearchStore.create();

const [keyword, setKeyword] = useState('');
const [hasSearched, setHasSearched] = useState(false);
const [isLoading, setIsLoading] = useState(false);

const handleSearch = async () => {
const nextKeyword = keyword.trim();
if (!nextKeyword) {
return;
}

setIsLoading(true);
setHasSearched(true);
try {
await search([nextKeyword], {
pageSize: 20,
searchScope: [SearchType.User],
});
} finally {
setIsLoading(false);
}
};

const handleLoadMore = async () => {
setIsLoading(true);
try {
await searchMore(SearchType.User);
} finally {
setIsLoading(false);
}
};

return (
<div className="search-store-basic-demo">
<div className="search-store-basic-demo__header">
<h2>Search Store Basic</h2>
<p>Very simple user search powered by SearchStore.</p>
</div>

<div className="search-store-basic-demo__toolbar">
<input
onChange={event => setKeyword(event.target.value)}
onKeyDown={event => {
if (event.key === 'Enter') {
handleSearch();
}
}}
placeholder="Enter user keyword"
value={keyword}
/>
<button disabled={isLoading || !keyword.trim()} onClick={handleSearch} type="button">
{isLoading ? 'Searching...' : 'Search'}
</button>
</div>

<div className="search-store-basic-demo__panel">
<h3>Users ({userTotalCount})</h3>
{userList.length > 0 ? (
<ul className="search-store-basic-demo__list">
{userList.map(user => (
<li className="search-store-basic-demo__item" key={user.userID}>
<span className="search-store-basic-demo__avatar">
{(user.nickname || user.userID).slice(0, 1).toUpperCase()}
</span>
<span>
<strong>{user.nickname || user.userID}</strong>
<small>{user.userID}</small>
</span>
</li>
))}
</ul>
) : (
<div className="search-store-basic-demo__empty">
{hasSearched ? 'No users found.' : 'Enter a keyword and search.'}
</div>
)}
</div>

{hasMoreUsers && (
<button
className="search-store-basic-demo__more"
disabled={isLoading}
onClick={handleLoadMore}
type="button"
>
Load More
</button>
)}
</div>
);
}
.search-store-basic-demo {
display: flex;
height: 100%;
flex-direction: column;
gap: 16px;
padding: 24px;
overflow: hidden;
}

.search-store-basic-demo__header h2 {
margin: 0 0 8px;
color: #111827;
font-size: 22px;
}

.search-store-basic-demo__header p {
margin: 0;
color: #6b7280;
font-size: 14px;
}

.search-store-basic-demo__toolbar {
display: flex;
gap: 8px;
}

.search-store-basic-demo__toolbar input {
width: 260px;
padding: 8px 10px;
border: 1px solid #d7dce5;
border-radius: 8px;
}

.search-store-basic-demo__toolbar button,
.search-store-basic-demo__more {
padding: 8px 12px;
border: 1px solid #667eea;
border-radius: 8px;
background: #667eea;
color: #fff;
cursor: pointer;
}

.search-store-basic-demo__toolbar button:disabled,
.search-store-basic-demo__more:disabled {
opacity: 0.6;
cursor: not-allowed;
}

.search-store-basic-demo__panel {
display: flex;
width: min(560px, 100%);
min-height: 0;
flex: 1;
flex-direction: column;
overflow: hidden;
border: 1px solid #edf0f5;
border-radius: 12px;
background: #fff;
}

.search-store-basic-demo__panel h3 {
margin: 0;
padding: 14px 16px;
border-bottom: 1px solid #edf0f5;
color: #111827;
font-size: 15px;
}

.search-store-basic-demo__list {
display: flex;
flex-direction: column;
gap: 8px;
margin: 0;
padding: 12px;
overflow: auto;
list-style: none;
}

.search-store-basic-demo__item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px;
border-radius: 10px;
background: #f9fafb;
}

.search-store-basic-demo__avatar {
display: inline-flex;
width: 32px;
height: 32px;
align-items: center;
justify-content: center;
border-radius: 50%;
background: #eef2ff;
color: #4f46e5;
font-size: 13px;
font-weight: 700;
}

.search-store-basic-demo__item strong,
.search-store-basic-demo__item small {
display: block;
}

.search-store-basic-demo__item strong {
color: #111827;
font-size: 14px;
}

.search-store-basic-demo__item small {
margin-top: 2px;
color: #6b7280;
font-size: 12px;
}

.search-store-basic-demo__empty {
padding: 24px;
color: #6b7280;
text-align: center;
}

.search-store-basic-demo__more {
width: fit-content;
}

帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈