Sharing Component State#
Note
Parts of this document are still under construction π§
Sometimes, you want the state of two components to always change together. To do it, remove state from both of them, move it to their closest common parent, and then pass it down to them via props. This is known as βlifting state upβ, and itβs one of the most common things you will do writing code with ReactPy.
Synced Inputs#
In the code below the two input boxes are synchronized, this happens because they share
state. The state is shared via the parent component SyncedInputs
. Check the value
and set_value
variables.
from reactpy import component, hooks, html, run
@component
def SyncedInputs():
value, set_value = hooks.use_state("")
return html.p(
Input("First input", value, set_value),
Input("Second input", value, set_value),
)
@component
def Input(label, value, set_value):
def handle_change(event):
set_value(event["target"]["value"])
return html.label(
label + " ", html.input({"value": value, "on_change": handle_change})
)
run(SyncedInputs)
Filterable List#
In the example below the search input and the list of elements below share the same state, the state represents the food name.
Note how the component Table
gets called at each change of state. The
component is observing the state and reacting to state changes automatically,
just like it would do in React.
import json
from pathlib import Path
from reactpy import component, hooks, html, run
HERE = Path(__file__)
DATA_PATH = HERE.parent / "data.json"
food_data = json.loads(DATA_PATH.read_text())
@component
def FilterableList():
value, set_value = hooks.use_state("")
return html.p(Search(value, set_value), html.hr(), Table(value, set_value))
@component
def Search(value, set_value):
def handle_change(event):
set_value(event["target"]["value"])
return html.label(
"Search by Food Name: ",
html.input({"value": value, "on_change": handle_change}),
)
@component
def Table(value, set_value):
rows = []
for row in food_data:
name = html.td(row["name"])
descr = html.td(row["description"])
tr = html.tr(name, descr, value)
if not value:
rows.append(tr)
elif value.lower() in row["name"].lower():
rows.append(tr)
headers = html.tr(html.td(html.b("name")), html.td(html.b("description")))
table = html.table(html.thead(headers), html.tbody(rows))
return table
run(FilterableList)
[
{
"name": "Sushi",
"description": "Sushi is a traditional Japanese dish of prepared vinegared rice"
},
{
"name": "Dal",
"description": "The most common way of preparing dal is in the form of a soup to which onions, tomatoes and various spices may be added"
},
{
"name": "Pierogi",
"description": "Pierogi are filled dumplings made by wrapping unleavened dough around a savoury or sweet filling and cooking in boiling water"
},
{
"name": "Shish Kebab",
"description": "Shish kebab is a popular meal of skewered and grilled cubes of meat"
},
{
"name": "Dim sum",
"description": "Dim sum is a large range of small dishes that Cantonese people traditionally enjoy in restaurants for breakfast and lunch"
}
]
Note
Try typing a food name in the search bar.