JavaScript
UIKit Key Functions

Key Functions

This page explains key functions of Sendbird UIKit for React consisting of how to list channels, chat in a channel, configure channel settings, create a channel, and invite users.


Components

Implement UIKit for React by using the following components.

SendBirdProvider

SendBirdProvider is the context provider that passes the Chat SDK down to the child components, and is the most important component in UIKit for React. The React Context API is used to easily pass down data through components. By using the withSendBird() HOC, Sendbird Chat SDK for Javascript can be implemented in any component under the SendBirdProvider which has the following properties:

Properties
RequiredTypeDescription

appId

string

The APP_ID of the Sendbird application.

userId

string

The unique ID of the user.

OptionalTypeDescription

accessToken

string

The access token for the user. (Default: null)

theme

string

The themes available are light and dark. (Default: light)

nickname

string

The user’s nickname. (Default: null)

profileUrl

string

The URL of the user’s profile image. (Default: null)

userListQuery

interface

The query factory class to retrieve a list of custom users. (Default: Chat SDK's ApplicationUserListQuery)

Note : The App component internally manages the SendBirdProvider as well as other components and can be used to configure the above properties.

withSendBird()

The withSendBird() is an HOC that helps you access data in the Chat SDK, and internally supports the Channel, ChannelList and ChannelSettings. Using the withSendBird(), data stored in the SendBirdProvider state, which is stored through the React Context API, can be accessed. The withSendBird() can be used to not only implement chat features, but also to access stored data for further customization.

Note : The Chat SDK can be accessed at state.stores.sdkStore.sdk or using sendBirdSelectors.getSdk()

Light Color Skin
Copy
const CustomReactComponentWithSendBirdConsumer = withSendBird(CustomReactComponent, mapStateToProps);

sendBirdSelectors

sendBirdSelectors provides many useful selectors to perform various data operations and can also be used to write customized selectors. The main functionalities of sendBirdSelectors regarding the Chat SDK are:

FunctionDescription

getConnect

Connects a user to Sendbird server.
Signature: (store) => (userId, accessToken) => Promise<(User, error)>

getDisconnect

Disconnects a user from Sendbird server.
Signature: (store) => (userId, accessToken) => Promise<(_, error)>

getUpdateUserInfo

Updates a user’s nickname or profile image.
Signature: (store) => (userId, accessToken) => Promise<(User, error)>

getSdk

Returns the SDK instance of a given user.
Signature: (store) => sdk

getCreateChannel

Creates a new channel with params.
Signature: (store) => (GroupChannelParams) => Promise<(GroupChannel, error)>

getLeaveChannel

Leaves a channel.
Signature: (store) => (channelUrl) => Promise<(_, error)>

getSendUserMessage

Returns a promise chain which sends a user message to a specific channel.
Signature: (store) => (channelUrl, UserMessageParams) => Promise<(PendingMessage, error)> => Promise<(UserMessage, error)>

getSendFileMessage

Returns a promise chain to send a file message to a specific channel.
Signature: (store) => (channelUrl, FileMessageParams) => Promise<(PendingMessage, error)> => Promise<(FileMessage, error)>

getUpdateUserMessage

Updates a user message.
Signature: (store) => (channelUrl, messageId, UserMessageParams) => Promise<(UserMessage, error)>

getDeleteMessage

Deletes a user message.
Signature: (store) => (channelUrl, message) => Promise<(_, error)>

getResendUserMessage

Resends a failed user message.
Signature: (store) => (channelUrl, FailedUserMessage) => Promise<(Message, error)>

getResendFileMessage

Resends a failed file message.
Signature: (store) => (channelUrl, FailedFileMessage) => Promise<(FileMessage, error)>

The sample code below shows how to implement sendBirdSelectors with its properties.

getDisconnect
getSDK
getCreateChannel&more
getSendUserMessage&more
Light Color Skin
Copy
import {
    SendBirdProvider,
    withSendBird,
    sendBirdSelectors,
} from "sendbird-uikit";
import "sendbird-uikit/dist/index.css";

const MyButton = (props) => {
    <button onClick={() => props.disconnect().then((reject, response) => { ... }); }>
        > Disconnect
    </button>
}

const ButtonWithSendBird = withSendBird(MyButton, (state) => {
    disconnect: sendBirdSelectors.getDisconnect(state),
});

const App = () => {
    <SendBirdProvider appId={appId} userId={userId}>
        <div>
            <ButtonWithSendBird />
        </div>
    </SendBirdProvider>
}
Light Color Skin
Copy
import {
    SendBirdProvider,
    withSendBird,
    sendBirdSelectors,
} from "sendbird-uikit";
import "sendbird-uikit/dist/index.css";

const Welcome = ({ currentUser }) => (
    <div>
        {`Hello, ${currentUser || 'unknown user'}`}
    </div>
);

const WelcomeWithSendBird = withSendBird(Welcome, (state) => {
    const sdk = sendBirdSelectors.getSdk(state);
    const currentUser = sdk && sdk.getCurrentUserId && sdk.getCurrentUserId();
    return ({ currentUser });
});

const GetSdkExample = () => (
    <SendBirdProvider appId={appId} userId={userId} nickname={userId}>
        <WelcomeWithSendBird />
    </SendBirdProvider>
)
Light Color Skin
Copy
// getCreateChannel & getLeaveChannel
import {
    SendBirdProvider,
    withSendBird,
    sendBirdSelectors,
} from "sendbird-uikit";
import "sendbird-uikit/dist/index.css";

const appId = process.env.APP_ID;
const userId = process.env.USER_ID;
const channelUrl = process.env.CHANNEL_URL;

const CustomComponent = ({ createChannel, sdk, leaveChannel }) => {
    const [channelUrl, setChannelUrl] = useState('');
    return(
        <>
            <button onClick={() => {
                let params = new sdk.GroupChannelParams();
                params.isPublic = false;
                params.isEphemeral = false;
                params.isDistinct = false;
                params.addUserIds(['sravan']);
                params.name = NAME;
                createChannel(params)
                    .then(c => {
                        setChannelUrl(c.url);
                    })
                    .catch(c => console.warn(c));
                }}
                > Create channel
            </button>
            <button onClick={() => {
                leaveChannel(channelUrl).
                    then(c => {
                        setChannelUrl('');
                    })
                    .catch(c => console.warn(c));
                }}
                > Leave channel
            </button>
            <br />
            { `Created channel is: ${channelUrl}` }
        </>
    );
};

const CustomComponentWithSendBird = withSendBird(CustomComponent, (state) => {
    const createChannel = sendBirdSelectors.getCreateChannel(state);
    const leaveChannel = sendBirdSelectors.getLeaveChannel(state);
    const sdk = sendBirdSelectors.getSdk(state);
    return ({ createChannel, sdk, leaveChannel });
});

export const ChannelCRUDSelectors = () => (
    <SendBirdProvider appId={appId} userId={userId} nickname={userId}>
        <CustomComponentWithSendBird />
        <div style={{ width: '320px', height: '500px' }}>
            <ChannelList />
        </div>
    </SendBirdProvider>
);
Light Color Skin
Copy
// getSendUserMessage & getSendFileMessage & getDeleteMessage & getUpdateUserMessage
import {
    SendBirdProvider,
    withSendBird,
    sendBirdSelectors,
} from "sendbird-uikit";
import "sendbird-uikit/dist/index.css";

const appId = process.env.APP_ID;
const userId = process.env.USER_ID;
const channelUrl = process.env.CHANNEL_URL;

const CustomComponent = (props) => {
    const {
        sendMessage,
        sendFileMessage,
        deleteMessage,
        updateLastMessage,
        sdk,
    } = props;
    const [lastMessage, setLastMessage] = useState({});
    const lastMessageId = lastMessage.messageId;
    return(
        <div onSubmit={e => e.preventDefault()}>
            {`Last MessageId: ${lastMessageId}`}
            <button onClick={() => {
                const params = new sdk.UserMessageParams();
                params.message = MESSAGE;
                sendMessage(channelUrl, params)
                    .then((pendingMessage) => {
                        setLastMessage(pendingMessage);
                        alert('Message is pending', pendingMessage);
                        return pendingMessage;
                    })
                    .then(message => {
                        alert('Message successfully sent', message);
                        setLastMessage(message);
                        console.warn(message);
                    })
                    .catch(e => {
                        console.warn(e);
                        alert('Couldn\'t send message.');
                    })
                }}
                > Send message
            </button>
            <button disable={!lastMessageId} onClick={() => {
                const params = new sdk.UserMessageParams();
                params.message = UPDATED_MESSAGE;
                updateLastMessage(channelUrl, lastMessageId, params)
                    .then((message) => {
                        setLastMessage(message);
                        alert('Message updated');
                    })
                    .catch(e => alert('Couldn\'t update a message.'))
                }}
                > Update last message
            </button>
            <button disable={!lastMessageId} onClick={() => {
                deleteMessage(channelUrl, lastMessage)
                    .then(() => {
                        alert('Message deleted');
                    })
                    .catch(e => {
                        console.warn(e);
                        alert('Couldn\'t delete a message.')
                    })
                }}
                > Delete last message
            </button>
            <br/>
            <input type="file" id="file-upload" />
            <button onClick={() => {
                const params = new sdk.FileMessageParams();
                params.file = document.getElementById('file-upload').files[0];
                sendFileMessage(channelUrl, params)
                    .then((pendingMessage) => {
                        setLastMessage(pendingMessage);
                        alert('Message is pending', pendingMessage);
                        return pendingMessage;
                    })
                    .then(message => {
                        alert('Message successfully sent', message);
                        setLastMessage(message);
                        console.warn(message);
                    })
                    .catch(e => alert('Couldn\'t delete message.'))
                    }}
                > Send file Message
            </button>
            </div>
    );
};

const CustomComponentWithSendBird = withSendBird(CustomComponent, (state) => {
    const sendMessage = sendBirdSelectors.getSendUserMessage(state);
    const sendFileMessage = sendBirdSelectors.getSendFileMessage(state);
    const deleteMessage = sendBirdSelectors.getDeleteMessage(state);
    const updateLastMessage = sendBirdSelectors.getUpdateUserMessage(state);
    const sdk = sendBirdSelectors.getSdk(state);
    return ({
        sendMessage,
        sendFileMessage,
        deleteMessage,
        updateLastMessage,
        sdk,
    });
});

export const MessageCRUDSelectors = () => (
    <SendBirdProvider appId={appId} userId={userId} nickname={userId}>
        <CustomComponentWithSendBird />
        <div style={{ width: '320px', height: '500px' }}>
            <Channel channelUrl={channelUrl} />
            </div>
    </SendBirdProvider>
);

App

The App component is a collection of all UIKit components needed to implement chat, and only requires the app ID and user ID to be configured.

Properties
RequiredTypeDescription

appId

string

The APP_ID of the Sendbird application.

userId

string

The unique ID of the user.

OptionalTypeDescription

accessToken

string

The access token for the user. (Default: null)

theme

string

The themes available are light and dark. (Default: light)

nickname

string

The user’s nickname. (Default: null)

profileUrl

string

The URL of the user’s profile image. (Default: null)

userListQuery

interface

The query factory class to retrieve a list of custom users. (Default: Chat SDK's ApplicationUserListQuery)

Light Color Skin
Copy
// Create a chat application
import { App } from "sendbird-uikit";
import "sendbird-uikit/dist/index.css"; 

const MyApp = () => {
    <Route id={'/chat'}>
        <App
            appId={appId}
            userId={userId}
            nickname={nickname}
            profileUrl={profileUrl}
            accessToken={accessToken}
            theme={theme}
            userListQuery={userListQuery}
        />
    </div>
}

Customize the user list

When creating a channel or inviting users to a channel, UIKit shows the user list page to enable user selection. The user list can be customized by receiving the UserListQuery implementation in the SendBirdProvider. If not given, all the users in the application are fetched through the Chat SDK’s ApplicationUserListQuery by default. Implement the UserListQuery as follows:

Light Color Skin
Copy
interface UserListQuery {
    hasNext: boolean;
    next(callback): void;
}

Implement the interface as follows:

Light Color Skin
Copy
// A member must have these three properties and the userId must be unique.
const Member = () => ({
    userId,
    profileUrl,
    nickname,
});

class CustomUserPaginatedQuery {
    constructor() {
        // Required public property to determine if more data is available.
        this.hasNext = false;
    }

    // Required public property.
    next(callback) {
        // Make async call and get list of users
        const [users, error] = myAsyncCallToGenerateMembers();
        // Set this.hasNext
        this.hasNext = setTrueIfMoreMembersCanBeFetched();
        callback(users, error);
    }
}

const CustomUserPaginatedQueryFactory = () => new CustomUserPaginatedQuery();

Apply the query as follows:

Light Color Skin
Copy
import { App } from "sendbird-uikit";
import "sendbird-uikit/dist/index.css"; 

const MyApp = () => {
    <Route id={'/chat'}>
        <App userId={userId} appId={appId} userListQuery={CustomUserPaginatedQueryFactory} />
    </div>
}

List channels

You can list channels by using the ChannelList component. Once a client app is connected to Sendbird server, the list of channels in the client app will be displayed by passing the ChannelList.

ChannelList

How to use

In order to use the ChannelList, it must be included in the SendBirdProvider. If the SendBirdProvider is placed at the top level, you can use the ChannelList anywhere in your application. The ChannelList has no minimum height and follows the height of the container, so it is recommended to specify the height of the wrapper element to fit your needs.

Properties
OptionalTypeDescription

renderChannelPreview

ReactElement

A custom component to replace the default channelPreview component. The following are given as arguments:
- channel: GroupChannel
- onLeaveChannel: function(channel, callback)

onChannelSelect

function

The prop to execute custom operations when listing the group channels selected by the current user. (Default: null)

onBeforeCreateChannel

function

The prop to execute custom operations before creating a channel.
- Function signature: fn(selectedUSers) => { return GroupChannelParams }

queries.channelListQuery

instance

A GroupChannelListQuery instance to filter channels by using its options.

queries.applicationUserListQuery

instance

An ApplicationUserListQuery instance to retrieve users when creating a channel.

Note : Static methods and keys such as next() or hasMore should not be overriden when customizing queries.

The sample codes below show how to implement ChannelList with its properties.

renderChannelPreview&more
onBeforeCreateChannel
queries.channelListQuery&more
Light Color Skin
Copy
// renderChannelPreview & onChannelSelect
import { ChannelList, SendBirdProvider} from "sendbird-uikit";
import "sendbird-uikit/dist/index.css";

const MyCustomPreview = ({ channel, onLeaveChannel }) => (
    <div style={{ border: '1px solid gray' }}>
        <img height="20px" width="20px" src={channel.coverUrl} />
        <button onClick={() => {
            const callback = () => {
                console.warn('Leave channel success')
            };
            onLeaveChannel(channel, callback);
            }}
            > Leave
        </button>
    </div>
);

const App = () => (
    <SendBirdProvider appId={appId} userId={userId}>
        <div style={{ height: '520px' }}>
            <ChannelList renderChannelPreview={MyCustomPreview}
                onChannelSelect={(channel) => { console.warn(channel); }}
            />
        </div>
    </SendBirdProvider>
);
Light Color Skin
Copy
const ChannelWithOnBeforeCreateChannel = ({ sdk }) => (
    <div style={{ height: '520px' }}>
        <ChannelList onBeforeCreateChannel={(selectedUsers) => {
                if (!sdk || !sdk.GroupChannelParams) { return }
                const params = new sdk.GroupChannelParams();
                params.addUserIds(selectedUsers);
                params.name = CUSTOM_NAME;
                return params;
            }}
        />
    </div>
)

const ConnectedChannelList = withSendBird(ChannelWithOnBeforeCreateChannel, (store) => ({
    sdk: getSdk(store),
}))

export const onBeforeCreateChannel = () => (
    <Sendbird appId={appId} userId={userId}>
        <ConnectedChannelList />
    </Sendbird>
);
Light Color Skin
Copy
// queries.channelListQuery & queries.applicationUserListQuery
export const CustomQueryExample = () => (
    <Sendbird appId={appId} userId={userId}>
        <ChannelList queries={{
            channelListQuery: {
                includeEmpty: true,
                order: 'latest_last_message',
            },
            applicationUserListQuery: {
                limit: 30,
                userIdsFilter: ['katherine', 'cindy'],
            },
        }}
        />
    </Sendbird>
);

Chat in a channel

Configure to display channel messages using the Channel component. Similar to the ChannelList, the Channel component also must be included in the SendBirdProvider. If you place the SendBirdProvider on the top level, you can use the Channel anywhere in your application. The Channel has no minimum height and follows the height of the container, so it is recommended to specify the height of the wrapper element to fit your needs.

Channel

How to use

Use the following code to import Channel:

Properties
RequiredTypeDescription

channelUrl

string

The unique URL of the channel.

OptionalTypeDescription

renderChatItem

ReactElement

A custom header to replace the default message header. The following are given as arguments:
- message: BaseMessage
- onUpdateMessage: function(messageId, message, callback)
- onDeleteMessage: function(message, callback)

renderChatHeader

ReactElement

A custom header to replace the default channel header. The following are given as arguments:
- channel: GroupChannel, user: User

renderMessageInput

ReactElement

A custom input to replace the default message input. The following are given as arguments:
- channel: GroupChannel, user: User, disabled: Boolean

onChatHeaderActionClick

function

The prop to execute custom operations when the top-right icon on the header has been clicked. (Default: null)

onBeforeSendUserMessage

function

The prop to execute additional operations for a user message. The modified user message is returned through the UserMessageParams before sending it.
- Function signature: fn(text) => { return UserMessageParams }

onBeforeSendFileMessage

function

The prop to execute additional operations for a file message. The modified file message is returned through the FileMessageParams before sending it.
- Function signature: fn(file) => { return FileMessageParams }

onBeforeUpdateUserMessage

function

The prop to execute additional operations for a user message before updating it.
- Function signature: fn(text) => { return UserMessageParams }

queries.messageListParams

instance

A query instance to retrieve a list of messages by specifying the properties of MessageListParams.

The sample codes below show how to implement Channel with its properties.

renderChatItem
renderChatHeader&more
onBeforeSendUserMessage&more
queries.messageListParams
Light Color Skin
Copy
import { Channel, SendBirdProvider } from "sendbird-uikit";
import "sendbird-uikit/dist/index.css"; 

const MyCustomChatMessage = ({ message, onDeleteMessage, onUpdateMessage }) => (
    <div>
        {message.message}
        <button onClick={() => {
            const callback = () => { console.warn('message deleted'); }
            onDeleteMessage(message, callback);
            }}
            > Delete
        </button>
        <button onClick={() => {
            const updatedMessage = Math.random().toString();
            const callback = () => { console.warn('message updated'); }
            onUpdateMessage(message.messageId, updatedMessage, callback);
            }}
            > Update
        </button>
    </div>
);

const App = () => (
    <SendBirdProvider appId={appId} userId={userId}>
        <div style={{ height: '500px' }}>
            <Channel channelUrl={channelUrl} renderChatItem={MyCustomChatMessage} />
        </div>
    </SendBirdProvider>
);
Light Color Skin
Copy
// renderChatHeader & renderMessageInput 
import { Channel, SendBirdProvider as SendBird, withSendBird, sendBirdSelectors } from "sendbird-uikit";
import "sendbird-uikit/dist/index.css"; 

const CustomChatHeader = ({ channel, user }) => (
    <div style={{ border: '1px solid red' }}>- {channel.name} / {user.nickname}</div>
);

const CustomInput = ({ channel, user, sendMessage, sdk, disabled }) => {
    const ref = useRef();
    return (
    <div>
        <input disabled={disabled} onChange={() => { channel.startTyping() }} ref={ref} />
        <button onClick={() => {
                const value = ref.current.value;
                const params = new sdk.UserMessageParams();
                params.message = value;
                sendMessage(channel.url, params)
                ref.current.value = '';
            }}
            > Send
        </button>
    </div>
  );
}

const CustomInputWithSendbird = withSendBird(CustomInput, (state) => {
    const sendMessage = sendBirdSelectors.getSendUserMessage(state);
    const sdk = sendBirdSelectors.getSdk(state);
    return {
        sendMessage,
        sdk
    };
})

export const CustomHeaderAndInput = () => (
    <Sendbird appId={appId} userId={userId}>
        <div style={{ height: '500px' }}>
            <Channel channelUrl={channelUrl} renderChatHeader={CustomChatHeader} renderMessageInput={CustomInputWithSendbird} />
        </div>
    </Sendbird>
);
Light Color Skin
Copy
// onBeforeSendUserMessage & onBeforeSendFileMessage & onBeforeUpdateUserMessage
const ChannelWithOnBeforeActions = ({ sdk }) => (
    <div style={{ height: '520px' }}>
        <Channel channelUrl={channelUrl}
            onBeforeSendUserMessage={(text) => {
                const params = new sdk.UserMessageParams();
                params.message = text + EXTRA_MESSAGE;
                params.data = DATA;
                return params;
            }}
            onBeforeSendFileMessage={(file) => {
                const params = new sdk.FileMessageParams();
                params.file = file;
                params.data = DATA;
                return params;
            }}
            onBeforeUpdateUserMessage={(text) => {
                const params = new sdk.UserMessageParams();
                params.message = text + MESSAGE_TO_UPDATE;
                params.data = DATA;
                return params;
            }}
        />
    </div>
)

const ConnectedChannel = withSendBird(ChannelWithOnBeforeActions, (store) => ({
    sdk: getSdk(store),
}))

export const OnBeforeActionsChannel = () => (
    <Sendbird appId={appId} userId={userId}> <ConnectedChannel />
    </Sendbird>
);
Light Color Skin
Copy
export const CustomQueryExample = () => (
    <Sendbird appId={appId} userId={userId}>
        <div style={{ height: '520px' }}>
            <Channel
                channelUrl={channelUrl}
                queries={{
                    messageListParams: {
                        prevResultSize: 10,
                        includeParentMessageText: true,
                        includeReaction: false,
                    }
                }}
            />
        </div>
    </Sendbird>
);

Configure channel settings

Use the ChannelSettings component to show a list of channels or create a channel. Similar to the ChannelList and Channel, the ChannelSettings component also must be included in the SendBirdProvider. When the height of your wrapper component is specified, the ChannelList will assume this height. If you want to adjust width or other visual properties, you may need to use CSS.

ChannelSettings

How to use

Use the following code to import ChannelSettings:

Properties
RequiredTypeDescription

channelUrl

string

The unique URL of the channel.

OptionalTypeDescription

onCloseClick

function

The prop to execute custom operations when the close button has been clicked. (Default: null)

onChannelModified

function

The prop to execute custom operations when a channel has been modified. (Default: null)

onBeforeUpdateChannel

function

The prop to execute custom operations before updating a channel.
- Function signature: fn(channelTitle, channelImage, Channel.data) => { return GroupChannelParams }

queries.applicationUserListQuery

instance

An ApplicationUserListQuery instance in ChannelSettings to retrieve users who are invited to a channel.

The sample codes below show how to implement ChannelSettings with its properties.

onCloseClick&more
onBeforeUpdateChannel
queries.applicationUserListQuery
Light Color Skin
Copy
// onCloseClick & onChannelModified
import { ChannelSettings, SendBirdProvider } from "sendbird-uikit";
import "sendbird-uikit/dist/index.css"; 

const App = () => {
    <SendBirdProvider appId={appId} userId={userId}>
        <div style={{ height: '600px', textAlign: 'center' }}>
            <ChannelSettings channelUrl={channelUrl}
                onChannelModified-{channel => {...}}
                onCloseClick={() => { setShowSettings(false); }}
            />
        </div>
    </SendBirdProvider>
};
Light Color Skin
Copy
const ChannelWithOnBeforeUpdateChannel = ({ sdk }) => (
    <div style={{ height: '520px' }}>
        <ChannelSetting channelUrl={channelUrl}
            onBeforeUpdateChannel={(currentTitle, currentImg, channelData) => {
                if (!sdk || !sdk.GroupChannelParams) { return }
                const params = new sdk.GroupChannelParams();
                params.name = CUSTOM_NAME;
                return params;
            }}
        />
    </div>
)

const ConnectedChannelSettings = withSendBird(ChannelWithOnBeforeUpdateChannel, (store) => ({
    sdk: getSdk(store),
}))

export const OnBeforeUpdateChannel = () => (
    <Sendbird appId={appId} userId={userId}>
        <ConnectedChannelSettings />
    </Sendbird>
);
Light Color Skin
Copy
export const CustomQueryExample = () => (
    <Sendbird appId={appId} userId={userId}>
        <div style={{ height: '520px' }}>
            <ChannelSetting channelUrl={channelUrl}
                queries={{
                    applicationUserListQuery: {
                        limit: 30,
                        userIdsFilter: ['jeff'],
                    },
                }}
            />
        </div>
    </Sendbird>
);

Invite users

Custom user list can be implemented to the chat to create a new group chat or an 1-on-1 chat. You can also implement how to invite new members to your chat.

The ApplicationUserListQuery is used to invite users by default. Another way to invite users is fetching data to the App or SendBirdProvider components by passing a function. The implementation can be done by following the below sample code:

Light Color Skin
Copy
// A member must have these three properties and userId must be unique
const Member = () => ({
    userId,
    profileUrl,
    nickname,
});

class CustomUserPaginatedQuery {
    constructor() {
        // Required public property to determine if more data is available.
        this.hasNext = false;
    }

    // Required public property
    next(callback) {
        // Make an async call and get list of users.
        const [users, error] = myAsyncCallToGenerateMembers();
        // Set this.hasNext
        this.hasNext = setTrueIfMoreMembersCanBeFetched();
        callback(users, error);
    }
}

const getCustomPaginatedQuery = () => new CustomPaginatedQuery();

import { App } from "sendbird-uikit";
import "sendbird-uikit/dist/index.css"; 

const MyApp = () => {
    <Route id={'/chat'}>
        <App userId={userId} appId={appId} userListQuery={getCustomPaginatedQuery} />
    </div>
}