Here’s how to migrate React hooks from ably-js v1 to v2:
- Use new
ChannelProvider
component - Update usage of the
usePresence
hook, which has been split into two separate hooks - Rename optional
id
field toablyId
- (Optional) Use new convenience function
publish
inuseChannel
In previous versions, you were able to provide channel options as a parameter in the useChannel
/usePresence
hooks. This could, in some cases, lead to errors when using hooks with the same channel name but different options, or when attempting to dynamically change options for a channel.
To address these issues, the new version introduces the ChannelProvider
component to define the channels you wish to use and their options. The ability to provide channel options using the options
or deriveOptions
parameters in useChannel
/usePresence
hooks has been removed.
Replace code that used options
in the useChannel
hook:
const { channel } = useChannel(
{ channelName: 'your-channel-name', options: { params: { rewind: '1' } } },
(message) => {
console.log(message);
},
);
With this:
// in a parent component:
return (
<ChannelProvider channelName="your-channel-name" options={{ params: { rewind: '1' } }}>
{children}
</ChannelProvider>
);
// in a child component:
const { channel } = useChannel({ channelName: 'your-channel-name' }, (message) => {
console.log(message);
});
Replace code that used deriveOptions
in useChannel
hook:
useChannel(
{
channelName: 'your-derived-channel-name',
deriveOptions: { filter: 'headers.role == `"marketing"`' },
},
(message) => {
console.log(message);
},
);
With this:
// in a parent component:
return (
<ChannelProvider channelName="your-derived-channel-name" deriveOptions={{ filter: 'headers.role == `"marketing"`' }}>
{children}
</ChannelProvider>
);
// in a child component:
useChannel({ channelName: 'your-derived-channel-name' }, (message) => {
console.log(message);
});
Replace code that used options
in usePresence
hook:
const { updateStatus } = usePresence(
{ channelName: 'presence-channel-name', options: { modes: ['PRESENCE'] } },
{ foo: 'bar' },
);
With this:
// in a parent component:
return (
<ChannelProvider channelName="presence-channel-name" options={{ modes: ['PRESENCE'] }}>
{children}
</ChannelProvider>
);
// in a child component:
const { updateStatus } = usePresence({ channelName: 'presence-channel-name' }, { foo: 'bar' });
Additionally, if you were calling .setOptions()
on a channel instance returned by the useChannel
hook before, you must remove those calls and instead modify options provided to the ChannelProvider
component if you want to change channel options during runtime.
Change this:
const { channel } = useChannel({ channelName: 'your-channel-name' }, (message) => {
console.log(message);
});
channel.setOptions({ params: { rewind: '1' } });
To this:
// in a parent component:
// change channel options during runtime using state
const [options, setOptions] = useState({});
return (
<ChannelProvider channelName="your-channel-name" options={options}>
{children}
</ChannelProvider>
);
// in a child component:
const { channel } = useChannel({ channelName: 'your-channel-name' }, (message) => {
console.log(message);
});
// use the useState setter to change the options provided to the `ChannelProvider` component
setOptions({ params: { rewind: '1' } });
The functionality of the usePresence
hook has been split into two separate hooks.
The usePresence
hook can now only be used to enter the presence with optional initial state and update the presence status for the current client. It no longer returns the presenceData
value and does not accept the onPresenceUpdated
callback as its third parameter.
To listen for presence updates, a new hook called usePresenceListener
has been introduced. This hook returns the presenceData
object previously returned by usePresence
and accepts an onPresenceMessageReceived
callback as its second parameter, which is called on new presence messages.
Replace this:
const { presenceData, updateStatus } = usePresence(
{ channelName: 'presence-channel-name' },
{ foo: 'bar' },
(update) => {
console.log(update);
},
);
With this:
const { updateStatus } = usePresence({ channelName: 'presence-channel-name' }, { foo: 'bar' });
const { presenceData } = usePresenceListener({ channelName: 'presence-channel-name' }, (update) => {
console.log(update);
});
All instances of the id
field, which optionally were used to specify the AblyProvider
component and the underlying Ably client to use, have been renamed to ablyId
.
Replace this:
// in a parent component:
const client = new Ably.Realtime(options);
return (
<AblyProvider client={ably} id="foo">
{children}
</AblyProvider>
);
// in a child component:
useChannel({ channelName: 'your-channel-name', id: 'foo' }, (message) => {
console.log(message);
});
With this:
// in a parent component:
const client = new Ably.Realtime(options);
return (
<AblyProvider client={ably} ablyId="foo">
<ChannelProvider channelName="your-channel-name" ablyId="foo">
{children}
</ChannelProvider>
</AblyProvider>
);
// in a child component:
useChannel({ channelName: 'your-channel-name', ablyId: 'foo' }, (message) => {
console.log(message);
});
A new convenience function, publish
, is now being returned by the useChannel
hook. It performs the same function as calling channel.publish()
. Additionally, using this dedicated publish
function allows you to send messages to derived channels (channels with a filter qualifier) without attaching to the channel or using other workarounds.
It is recommended to use the dedicated publish
function returned by the useChannel
hook instead of calling channel.publish()
.
Replace this:
const { channel } = useChannel({ channelName: 'your-channel-name' });
channel.publish('test-message', {
text: 'message text',
});
With this:
const { publish } = useChannel({ channelName: 'your-channel-name' });
publish('test-message', {
text: 'message text',
});