use-pusher
Easy as hooks that integrate with the pusher-js library.
Install
yarn add @harelpls/use-pusher
Hooks
Usage
You must wrap your app with a PusherProvider
and pass it config props for pusher-js
initialisation.
import React from 'react';
import { PusherProvider } from '@harelpls/use-pusher';
const config = {
clientKey: 'client-key',
cluster: 'ap4',
triggerEndpoint: '/pusher/trigger',
authEndpoint: '/pusher/auth',
auth: {
headers: { Authorization: 'Bearer token' },
},
};
const App = () => {
<PusherProvider {...config}>
<Example />
</PusherProvider>;
};
useChannel
Use this hook to subscribe to a channel.
const channel = useChannel('channel-name');
usePresenceChannel
Augments a regular channel with member functionality.
const Example = () => {
const { members, myID } = usePresenceChannel('presence-awesome');
return (
<ul>
{Object.entries(members)
// filter self from members
.filter([id] => id !== myID)
// map them to a list
.map([id, info] => (
<li key={id}>{info.name}</li>
))
}
</ul>
)
}
useEvent
Bind to events on a channel with a callback.
const Example = () => {
const [message, setMessages] = useState();
const channel = useChannel('channel-name');
useEvent(
channel,
'message',
({ data }) => setMessages(messages => [...messages, data]),
[]
);
};
useTrigger
A helper function to create a server triggered event. BYO server (See Trigger Server below). Pass in triggerEndpoint
prop to <PusherProvider />
. Any auth headers from config.auth.headers
automatically get passed to the fetch
call.
import { useTrigger } from '@harelpls/use-pusher';
const Example = () => {.
const trigger = useTrigger();
const handleClick = () =>
trigger("channel-name", "event-name", "hello");
return (
<button onClick={handleClick}>Say Hello</button>
)
}
usePusher
Get access to the Pusher instance to do other things.
import { usePusher } from '@harelpls/use-pusher';
const Example = () => {
const { client } = usePusher();
client.log('Look ma, logs!');
return null;
};
Trigger Server
In order to trigger an event, you'll have to create a simple lambda (or an express server if that's your thing). Below is a short lambda that can handle triggered events from useTrigger
.
import Pusher from 'pusher';
const pusher = new Pusher({
appId: 'app-id',
key: 'client-key',
secret: 'mad-secret',
cluster: 'ap4',
});
export async function handler(event) {
const { channelName, eventName, data } = JSON.parse(event.body);
pusher.trigger(channelName, eventName, data);
return { statusCode: 200 };
}
I don't want a server though
I hear ya. If you're feeling audacious, you can use client events to push directly from the client:
import { useChannel, useClientTrigger } from '@harelpls/use-pusher';
const Example = () => {
const channel = useChannel('presence-danger-zone');
const trigger = useClientTrigger(channel);
const handleClientEvent = () => {
trigger('Pew pew');
};
return <button onClick={handleClientEvent}>Fire</button>;
};
Typescript
This project was built using typescript, so types are built-in. Yeeeew!
Testing
Typed PusherMock
, PusherChannelMock
and PusherPresenceChannelMock
utils are provided based on pusher-js-mock
(thanks mate 🙏). Use these to stub out the client and channels, with an additional emit
method on the channel classes.
Testing emitted events with jest can be achieved using jest.mock
and react-testing-library
(or enzyme
, though your tests should reflect what the user should see NOT how the component handles events internally):
import React from 'react';
import { useChannel, useEvent } from '@harelpls/use-pusher';
const Example = () => {
const [title, setTitle] = useState();
const channel = useChannel('my-channel');
useEvent(channel, 'title', ({ data }) => setTitle(data));
return <span>{title}</span>;
};
import { render, act } from '@testing-library/react';
import { PusherMock, PusherChannelMock } from '@harelpls/use-pusher';
const mockChannel = new PusherChannelMock();
jest.mock('@harelpls/use-pusher', () => ({
...require.requireActual('@harelpls/use-pusher'),
useChannel: () => mockChannel,
}));
test('should show a title when it receives a title event', async () => {
const client = { current: new PusherMock('client-key', { cluster: 'ap4' }) };
const { findByText } = render(
<PusherProvider clientKey="client-key" cluster="ap4" value={{ client }}>
<Example />
</PusherProvider>
);
act(() => mockChannel.emit('title', { data: 'Hello world' }));
expect(await findByText('Hello world')).toBeInTheDocument();
});
Check out the example tests for testing presence channels.
Contributing
- Clone the repository and run
yarn && yarn test:watch
- Get coding!
Please write tests (100% jest coverage) and types.
License
MIT © @mayteio
This hook is created using create-react-hook.