Reactive list of scalars
Reactive list of scalars¶
This example demonstrates rx[list[str]]: a reactive list field mutated in
place with ordinary Python list methods. Every append, insert,
__setitem__, del, pop and reassignment sends a small positional delta
to the client instead of re-sending the whole list, however many items it
holds.
Backend¶
from rxdjango import ContextChannel, rx, action
class ScalarListChannel(ContextChannel):
"""CRUD over a plain `rx[list[str]]` field.
Every action below is a single Python list mutator; the field
intercepts it and pushes a small delta to the client — no full-list
re-send, however many items are in the list.
"""
items = rx[list[str]](['apple', 'banana', 'cherry'])
@action
async def append(self, value: str):
self.items.append(value)
@action
async def insert(self, index: int, value: str):
self.items.insert(index, value)
@action
async def set_at(self, index: int, value: str):
self.items[index] = value
@action
async def remove_at(self, index: int):
del self.items[index]
@action
async def pop(self):
return self.items.pop()
@action
async def replace_all(self):
self.items = ['reset', 'from', 'scratch']
Frontend¶
import React, { useState } from 'react';
import { useChannel } from '@rxdjango/react';
import { ScalarListChannel } from '../../rx/scalar_list/scalar_list.channels';
import { Demo, Fields, Field, Button, TextInput, Row } from '../../components/demo';
export function ScalarListDemo() {
const channel = useChannel(ScalarListChannel);
const [draft, setDraft] = useState('');
const [setIndex, setSetIndex] = useState('0');
const [setValue, setSetValue] = useState('');
const appendDraft = () => {
if (!draft) return;
channel.append(draft);
setDraft('');
};
return (
<Demo>
<Fields>
<Field label="Items">
<ul className="space-y-2">
{channel.items.map((item, index) => (
<li
key={`${index}-${item}`}
className="flex items-center justify-between gap-3"
>
<span>
{item}
</span>
<Button
variant="secondary"
onClick={() => channel.remove_at(index)}
>
Remove
</Button>
</li>
))}
</ul>
</Field>
</Fields>
<Row>
<TextInput
id="scalar-list-draft"
label="New item"
value={draft}
onChange={setDraft}
/>
<Button onClick={appendDraft}>
Append
</Button>
</Row>
<Row>
<Button onClick={() => channel.insert(0, 'first')}>
Insert at start
</Button>
<Button onClick={() => channel.pop()}>
Pop last
</Button>
<Button variant="secondary" onClick={() => channel.replace_all()}>
Replace all
</Button>
</Row>
<Row>
<TextInput
id="scalar-list-set-index"
label="Set index"
value={setIndex}
onChange={setSetIndex}
/>
<TextInput
id="scalar-list-set-value"
label="Set value"
value={setValue}
onChange={setSetValue}
/>
<Button
variant="secondary"
onClick={() => channel.set_at(Number(setIndex), setValue)}
>
Set
</Button>
</Row>
</Demo>
);
}
export default ScalarListDemo;