Quickstart¶
This walkthrough sets up a minimal RxDjango app: a Django channel holding one reactive value, and a React component bound to it. RxDjango is working towards v0.1 and is not yet published on PyPI or npm — both packages install from the git repository for now.
Prerequisites¶
A Django project served over ASGI with Channels installed.
A running Redis. RxDjango broadcasts updates through the Channels channel layer, and the in-memory layer does not work across processes — use
channels_redis.A React app for the frontend.
Install¶
The backend package lives in the monorepo under packages/core:
pip install "rxdjango @ git+https://github.com/rxdjango/rxdjango#subdirectory=packages/core"
Model-backed state (rx.model, DRF serializers, reactive Django models)
comes from a second package:
pip install "rxdjango-model @ git+https://github.com/rxdjango/rxdjango#subdirectory=packages/model"
The React client is built from the repo and installed from its local path:
git clone https://github.com/rxdjango/rxdjango
cd rxdjango/packages/react
npm install && npm run build
cd /path/to/your-app
npm install /path/to/rxdjango/packages/react
Configure Django¶
In settings.py, add the apps and point RxDjango at your frontend:
INSTALLED_APPS = [
# ...
'rxdjango',
'channels',
# your apps
]
ASGI_APPLICATION = 'backend.asgi.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {'hosts': ['redis://127.0.0.1:6379/0']},
},
}
# Where generated TypeScript files are written, inside your React app.
RX_FRONTEND_DIR = BASE_DIR / '../frontend/src/app/rx'
# A JavaScript expression for the WebSocket URL, embedded in the
# generated client.
RX_WEBSOCKET_URL = "'ws://localhost:8000'"
Declare a channel¶
In an app’s channels.py:
from rxdjango import ContextChannel, rx, action
class CounterChannel(ContextChannel):
counter = rx[int](0)
@action
async def increment(self):
self.counter += 1
Route it in the app’s urls.py and include it in your ASGI websocket
router:
from django.urls import path
from .channels import CounterChannel
websocket_urls = [
path('ws/counter/', CounterChannel.as_asgi()),
]
# asgi.py
from channels.routing import ProtocolTypeRouter, URLRouter
from counter.urls import websocket_urls
application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket': URLRouter(websocket_urls),
})
Generate the TypeScript client¶
./manage.py makefrontend
This writes one module per app under RX_FRONTEND_DIR — for the channel
above, rx/counter/counter.channels.ts, exporting a typed
CounterChannel. Re-run it whenever a channel changes; it only rewrites
files whose declarations changed.
Use it from React¶
import { useChannel } from '@rxdjango/react';
import { CounterChannel } from './rx/counter/counter.channels';
export function Counter() {
const channel = useChannel(CounterChannel);
return (
<button onClick={channel.increment}>
{channel.counter}
</button>
);
}
useChannel opens the WebSocket, keeps channel.counter in sync with the
server, re-renders on every update, and exposes increment as a typed
async method. That is the whole integration — there is no consumer,
fetcher, or store to write.
From here, the Examples walk through the rest of the surface: computed fields, authorization, model-backed state, reactive lists, and live querysets.