use-pusher
Easy as hooks that integrate with the pusher-js library.
Install
yarn add 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 "@city-dna/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 '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 "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, though this isn't recommended (thus no hook):
import { useChannel } from "use-pusher";
const Example = () => {
const channel = useChannel("danger-zone");
const handleClientEvent = () => {
channel.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 "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 "use-pusher";
const mockChannel = new PusherChannelMock();
jest.mock("use-pusher", () => ({
...require.requireActual("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.