Add chatroom features #16
Open
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Steps
What is happening?
The realtime behavior is powered by ActionCable. Most of this setup is not related to Inertia at all. There is a useCable hook which would work in any React application. There are two places where Inertia is used:
Infinite Scroll
The messages in the chat drawer are rendered inside the Inertia.js
<InfiniteScroll />component. It has a few attributes set:reversetells the component to fetch the next page when you hit the top of a container (instead of fetching the previous page at the top of the container). Visually, the messages are reversed with theflex-col-reverseCSS property.onlyNexttells the component not to fetch previous pages. In our case that means "don't fetch pages when we scroll all the way to the bottom of the list".preserveUrlprevents the component from adding the page parameter to the URL. We don't need to be able to share links with the scroll position, so we don't need to track pagination in the URL.bufferfetches the next page a little bit before we hit the top of the container. We do this to avoid hitting the top of the container and triggering a lot of "next page" calls in quick succession.To fetch records backwards, the server just needs to sort in descending order. In our example, we're using the Pagy gem, but InertiaRails also supports Kaminari or even a custom pagination setup.
Receiving messages
Sending messages is done completely via React and ActionCable. Inertia isn't even involved. When the app receives a broadcast from ActionCable, the one Inertia line is in
<Chat />:This is a client side visit. Unlike in #14 , here we do not want to update the page history, so we are using
router.replaceinstead ofrouter.push(.prependToPropis a shortcut for.replace).Inertia is a protocol, not a framework. Most of the time we want to stay within the boundaries of Inertia request/response cycle. But not always! Websockets is a different protocol, and it is more appropriate for things like realtime chat. All we need to integrate back into Inertia is to merge the data back into Inertia's Page props. Client side visits are perfect for this! The same technique would work if we made a request to a pure JSON API outside of Inertia.
Auto scroll
In
<ChatDrawer />, we have auseEffectthat automatically scrolls our chat message container to the bottom when a new message comes in. This is purely React code; it has nothing to do with Inertia. But it's worth looking at. An Inertia application should have feweruseEffectcalls in it. So you might wonder if you should should never have auseEffect. This is a good use case for one: we want to automatically scroll as a side effect of the chat message list growing larger. Because this update comes from outside Inertia, the code is more cohesive watching the chat messages array than trying to hook into ActionCable's receive method. It's a good rule of thumb to try to use Inertia as much as possible. But Inertia still leaves you will the full power of React when you need it!