Easy as React hooks that integrate with the
pusher-js
library.
- Install
- Hooks
- Usage
useChannel
usePresenceChannel
useEvent
useTrigger
usePusher
- Trigger Server
useClientTrigger
- Typescript
- Testing
- React Native
- Contributing
- License
yarn add @harelpls/use-pusher
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 = {
// required config props
clientKey: "client-key",
cluster: "ap4",
// optional if you'd like to trigger events. BYO endpoint.
// see "Trigger Server" below for more info
triggerEndpoint: "/pusher/trigger",
// required for private/presence channels
// also sends auth headers to trigger endpoint
authEndpoint: "/pusher/auth",
auth: {
headers: { Authorization: "Bearer token" },
},
};
// Wrap app in provider
const App = () => {
<PusherProvider {...config}>
<Example />
</PusherProvider>;
};
Use this hook to subscribe to a channel.
// returns channel instance.
const channel = useChannel("channel-name");
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>
)
}
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])
);
};
Note: This will bind and unbind to the event on each render. You may want to memoise your callback with useCallback
before passing it in if you notice performance issues.
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("channel-name");
const handleClick = () =>
trigger("event-name", "hello");
return (
<button onClick={handleClick}>Say Hello</button>
)
}
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;
};
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-ca");
const trigger = useClientTrigger(channel);
const handleClientEvent = () => {
trigger("Pew pew");
};
return <button onClick={handleClientEvent}>Fire</button>;
};
This project was built using typescript, so types are built-in. Yeeeew!
I've teamed up with @nikolalsvk on pusher-js-mock
to bring y'all a great pusher mock.
Testing emitted events with jest can be achieved using jest.mock
and @testing-library/react
(or enzyme
, though your tests should reflect what the user should see NOT how the component handles events internally):
// Example.tsx
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>;
};
// Example.test.tsx
import { render, act } from "@testing-library/react";
import { PusherMock, PusherChannelMock } from "pusher-js-mock";
// mock out the result of the useChannel hook
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 () => {
// mock the client
const client = new PusherMock("client-key", { cluster: "ap4" });
// render component and provider with a mocked context value
const { findByText } = render(
<PusherProvider clientKey="client-key" cluster="ap4" value={{ client }}>
<Example />
</PusherProvider>
);
// emit an event on the mocked channel
act(() => mockChannel.emit("title", { data: "Hello world" }));
// assert expectations
expect(await findByText("Hello world")).toBeInTheDocument();
});
Check out the example tests for testing presence channels.
This package comes with React Native support. Import your PusherProvider
from @harelpls/use-pusher/react-native
instead of the default @harelpls/use-pusher
. All exports are re-exported from there.
Ensure you add the netinfo package to your project too: @react-native-community/netinfo
.
import { PusherProvider, useChannel } from "@harelpls/use-pusher/react-native";
- Clone the repository and run
yarn && yarn test:watch
- Get coding!
Please write tests (100% jest coverage) and types.
MIT Β© @mayteio
This hook is created using create-react-hook.