Retink is a library for building reactive user interfaces in Python. It is inspired by React and uses tkinter as the backend.
from retink import run, Text, component
@component
def App():
return Text("hello"), Text("world")
run(App)Each component is a function with the @component decorator, that returns one or more widgets.
The component whose function is run (using the run function)is the root component.
from retink import run, Text, Button, component, create_state
@component
def App():
count, set_count = create_state(0)
return Button(
f"Clicked {count} time(s)",
on_click=lambda: set_count(count + 1)
)
run(App)Use create_state to create a stateful value. The first argument is the initial value, the second is a setter function.
from retink import run, Text, Button, component, create_state, create_effect
@component
def App():
count, set_count = create_state(0)
create_effect(lambda: print(count), [count])
return Button(
f"Clicked {count} time(s)",
on_click=lambda: set_count(count + 1)
)
run(App)Use create_effect to create an effect. The first argument is the function to run, the second is a list of stateful values that the function depends on.
from retink import run, Text, Button, component, create_state, create_effect
@component
def App():
count, set_count = create_state(0)
create_effect(lambda: print(count), [count])
return View([
Text(f"Clicked {count} time(s)"),
Button("Click me", on_click=lambda: set_count(count + 1))
])
run(App)Use View to group multiple widgets together. The widgets are laid out horizontally by default. But you can use row=True to lay them out vertically.
from retink import run, Text, Button, component, create_state, create_effect
@component
def App():
count, set_count = create_state(0)
create_effect(lambda: print(count), [count])
return View([
Text(f"Clicked {count} time(s)"),
Button("Click me", on_click=lambda: set_count(count + 1)),
], row=True)
run(App)Note: When we return multiple widgets from a component, they are wrapped in a View implicitly.
from retink import run, Text, Button, component, create_state, create_effect
@component
def App():
count, set_count = create_state(0)
even_ui = Text("even")
odd_ui = Text("odd")
label = even_ui if count % 2 == 0 else odd_ui
return View([
label,
Button("Click me", on_click=lambda: set_count(count + 1)) if count < 5 else Text("Clicked too many times")
])
run(App)Since UI is just a python function, and views are just python lists, we can use python's conditional statements to render different UIs.
from retink import run, Text, Button, component, create_state, create_effect
@component
def App():
todos, set_todos = create_state([])
def add_todo(text):
set_todos(todos + [text])
return View([
Text("Enter a todo:"),
TextInput(on_change=add_todo),
*(Text(text) for text in todos)
])
run(App)Use * to unpack a list of widgets into a list of widgets.
from retink import run, Image, component
@component
def App():
return Image("path/to/image.png")
run(App)Use Image to display an image.
See todo.py for a complete example of a todo app.
Download the repo and run pip install . in the root directory.