Server-sent events send request
use hook
Before using extended hooks, make sure you are familiar with the basic use of alova.
Features
- A simpler and easier way to use;
- Automatically manage connections;
In [3.3.0+], this strategy is implemented using fetch, which means you can specify all fetch parameters such as headers and method in the streaming request, while in previous versions it was implemented using EventSource.
Usage
import { useSSE } from 'alova/client';
const postMethodHandler = (value: string) => alova.Post('/api/source', null, {
headers: { 'Content-Type': 'application/json' },
param: { key: value }
});
const {
// Received data, each reception will modify data
data,
// Current EventSource instance
eventSource,
// Connection status, 0-connecting, 1-open, 2-closed
readyState,
// Bind connection event
onOpen,
// Bind message reception
onMessage,
// Bind error event
onError,
// Bind custom event
on,
// Connect and send message
send,
// Close connection
close
} = useSSE(postMethodHandler, {
credentials: 'include',
initialData: 'initial-data' // Data in data at the beginning
// ...other parameters of fetch
});
Send request
By default, no request will be sent. You need to call send
to send the request, or you can set immediate = true
to send the request immediately.
const { data, eventSource, readyState, onMessage, onError, on, send, close } = useSSE(
postMethodHandler,
{
immediate: true
}
);
useSSE
can only connect to one source at present. That is, when trying to connect to multiple targets, the previous connection will always be disconnected.
const { data, eventSource, readyState, onMessage, onError, on, send, close } =
useSSE(postMethodHandler);
send('value1');
send('value2'); // This will disconnect the previous connection
send('value3'); // This will also disconnect the previous connection
Receive data
When data is received, it will automatically be assigned to the state data
. You can bind it directly to the view, or listen to it to perform some operations.
- vue
- react
- svelte
- solid
<template>
<div>
<span v-if="readyState === 0">Connecting</span>
<span v-else-if="readyState === 1">Connected</span>
<span v-else-if="readyState === 2">Disconnected</span>
</div>
<div>Last received data: {{data}}</div>
<ul>
<li
v-for="item in dataList"
:key="item">
{{item}}
</li>
</ul>
<button @click="send">Connect</button>
<button @click="close">Close</button>
</template>
<script setup>
import { ref } from 'vue';
const { data, readyState, onMessage, close, send } = useSSE(postMethodHandler);
const dataList = ref([]);
onMessage(({ data }) => {
dataList.value.push(data);
});
</script>
import { useEffect, useState } from 'react';
const App = () => {
const [dataList, setDataList] = useState([]);
const { data, readyState, onMessage, onError, close, send } = useSSE(postMethodHandler);
onMessage(({ data }) => {
setDataList(prevList => [...prevList, data]);
});
return (
<div>
<span>
{readyState === 0 ? 'Connecting' : readyState === 1 ? 'Connected' : 'Disconnected'}
</span>
<div>Last received data: {data}</div>
<ul>
{dataList.map(item => (
<li key={item}>{item}</li>
))}
</ul>
<button onClick={send}>Connect</button>
<button onClick={close}>Close</button>
</div>
);
};
<script>
let dataList = [];
const { data, readyState, onMessage, close, send } = useSSE(postMethodHandler);
onMessage(({ data: newData }) => {
dataList.push(newData);
data = newData;
});
</script>
<div>
<span
>{readyState === 0 ? 'Connecting' : readyState === 1 ? 'Connected' : 'Disconnected'}</span
>
<div>Last received data: {data}</div>
<ul>
{#each dataList as item}
<li>{item}</li>
{/each}
</ul>
<button on:click="{send}">Connect</button>
<button on:click="{close}">Close</button>
</div>
import { createSignal } from 'solid-js';
const App = () => {
const [dataList, setDataList] = createSignal([]);
const { data, readyState, onMessage, onError, close, send } = useSSE(postMethodHandler);
onMessage(({ data }) => {
setDataList(prevList => [...prevList, data]);
});
return (
<div>
<span>
{readyState() === 0 ? 'Connecting' : readyState() === 1 ? 'Connected' : 'Disconnected'}
</span>
<div>Last received data: {data()}</div>
<ul>
<For each={dataList()}>{item => <li key={item}>{item}</li>}</For>
</ul>
<button onClick={send}>Connect</button>
<button onClick={close}>Close</button>
</div>
);
};
Binding events
useSSE
provides a series of binding event methods, and will return the unbinding function when binding.
const { onMessage, onError, close } = useSSE(postMethodHandler);
// Corresponding to the message event of eventsource
const offMessage = onMessage(event => {
console.log(event.eventSource); // Current EventSource instance
console.log(event.data);
});
const offError = onError(event => {
console.log(event.eventSource); // Current EventSource instance
console.error('sse error', event.error);
close();
});
// Unbind event
offMessage();
offError();
In addition, you can also listen to custom EventSource events, which will call the addEventListener
binding of EventSource.
const { on } = useSSE(postMethodHandler);
// The following code will listen for events with the field `event: update`
const offUpdate = on('update', event => {
console.log(event.eventSource); // Current EventSource instance
console.log(event.data);
});
Global response interception
By default, response data is captured by the global response interceptor. If this is not the behavior you expect, you can turn it off manually.
const { data, readyState, onMessage, on } = useSSE(postMethodHandler, {
interceptByGlobalResponded: false // Now dataWill not be intercepted by response
});
Type declaration
const enum SSEHookReadyState {
CONNECTING = 0,
OPEN = 1,
CLOSED = 2
};
type SSEHookConfig = {
/**
* Will be passed to new EventSource
*/
withCredentials?: boolean;
/**
* Whether to intercept by responding of alova instance
* @default true
*/
interceptByGlobalResponded?: boolean;
/**
* Initial data
*/
initialData?: any;
/**
* Whether to initiate a request immediately
* @default false
*/
immediate?: boolean;
};
type SSEReturnType<S, Data> = {
readyState: ExportedType<SSEHookReadyState, S>;
data: ExportedType<Data | undefined, S>;
eventSource: ExportedType<EventSource | undefined, S>;
/**
* Manually initiate a request. This method is automatically triggered when `immediate: true` is used
* @param args request parameters, which will be passed to method
*/
send: (...args: any[]) => Promise<void>;
/**
* Close the connection
*/
close: () => void;
/**
* Register the callback function of EventSource open
* @param callback callback function
* @returns cancel the registration function
*/
onOpen(callback: SSEOnOpenTrigger): () => void;
/**
* Register the callback function of EventSource message
* @param callback callback function
* @returns cancel the registration function
*/
onMessage<T = Data>(callback: SSEOnMessageTrigger<T>): () => void;
/**
* Register the callback function of EventSource error
* @param callback callback function
* @returns cancel the registration function
*/
onError(callback: SSEOnErrorTrigger): () => void;
/**
* @param eventName event name, default exists `open` | `error` | `message`
* @param handler event handler
*/
on(
eventName: string,
handler: (event: AlovaSSEMessageEvent<S, E, R, T, RC, RE, RH>) => void
) => () => void;
};