Taula de continguts

React Py

50px

React Py és una llibreria que ens permet crear interfaces amb python sense emprar javascript.

Es basa, com fa ReactJS, en components per a construir la interfícies de l'aplicació client. Té l'avantatge d'utilitzar el llenguatge Python. Per a desenvolupadors habituats a treballar amb Django o Flask els hi resultarà molt més còmode que utilitzar Javascript.

Tot i així, els navegadors no són capaços d'executar codi en Python, i per tant, per a producció o per a proves en un navegador, l'entorn de desenvolupament compila el codi python a javascript

Trobaràs la seva documentació a https://reactpy.dev/docs/index.html.

Tot i estar força incomplerta podem veure com es codifiquen molts dels elements típics de ReactJS en ReactPy. Des d'esdeveniments al més pur estil de javascript, fins a Hooks com useState, useEffect, useContext, useReducer, useCallBack, useMemo i useRef

Un primer exemple

La millor forma d'entendre com funciona és creant un petit projecte.

Instal·lació de dependències

Primer començarem instal·lant les dependències

pip3 install 'reactpy[fastapi]'

fastapi només és necessari per a aixecar el projecte

Encabat instal·lem uvicorn, que ens permetrà aixecar l'entorn de desenvolupament. Seria l'equivalen al node que emprem amb ReactJS

pip3 install 'uvicorn[standard]'

Creació del primer component

Després d'això creem un fitxer main.py, on importarem les llibreries

from reactpy import component,html,hooks
from reactpy.backend.fastapi import  configure
from fastapi import FastAPI

#....

#Al final del codi
app = FastAPI()
configure (app, HelloWorld )

I creem el primer component

@component
def HelloWorld():
   return html.div("Hello World")

Observa com el retorn es fa emprant l'objecte html, i els elements que hi vulguem visualitzar.

Pots obtenir més informació a

HTML With ReactPy

Un altre exemple d'elements renderitzats per html. Observa com creem una estructura d'elements amb més elements i elements fills:

html.div(
    html.h1("My Todo List"),
    html.ul(
        html.li("Build a cool new app"),
        html.li("Share it with the world!"),
    ),
)

Esdeveniments

Els elements html també poden rebre esdeveniments, i això ho podem expressar com segueix:

return html.button({"on_click": handle_event}, display_text)

Tens més exemples a Responding to Events

Components amb estat

Com a ReactJS, un dels elements més potents que tenen aquests frameworks són els estats. A ReactPy també tenim aquesta opció, com esmentavem abans, i ens permet renderitzar el nostre SPA a canvis de qualsevol valor. A Components with state tens més exemples.

Un exemple senzill:

choices, set_choices = hooks.use_state([])
resposta, set_resposta = hooks.use_state("")

Aquí creem dues variable d'estat, la primera inicialitzada amb un array, i la segona amb una cadena de text

En un mètode que gestioni un esdeveniment podem, per exemple, canviar el seu valor:

def handle_choices(event):
   set_resposta("Gràcies per la teva resposta")

I aquesta variable d'estat renderitzar-se amb el component

return html.div(resposta)

Cal recordar, que a l'igual que amb ReactJS, un canvi de valor d'una variable d'estat que es rendertiza en l'html, obliga re-rendertizar l'html, sempre sense recàrrega de l'html, ja que és un spa.

Finalment indicar que tenim altres hooks, propis de React, com ja he esmentat a l'inici de l'article, però que aquí no detallarem

Teniu un repositori de github on podeu veure un projecte sencer. En ell es consulta dues API's per oblir dos select

A cotinuació es mostra un fragment del codi

from reactpy import component,html,hooks   
from reactpy.backend.fastapi import  configure
from fastapi import FastAPI

import requests

@component
def Item(text, initial_done=False):
    done, set_done = hooks.use_state(initial_done)

    def handle_click(event):
      set_done(not done)
    
    attr= {"style": {"color": "green"}} if done else {"style": {"color": "red"}}

    if done:
       return html.li(attr, text)
    else:
       return html.li(
          html.span(attr, text),
          html.button({ "on_click": handle_click }," Fet!")
       )

@component
def Todos(items): 
   
   choices, set_choices = hooks.use_state([])
   resposta, set_resposta = hooks.use_state("")

   def handle_choices(event):
      set_resposta("Gràcies per la teva resposta")

   def handle_click(event):
      id = event['target']['value']
      # obtenim llista de choices
      choices_API = requests.get('http://localhost:8002/api/get_choices/'+id)
      resultat = choices_API.json()
      items_choices= resultat['choices']
      set_choices( [
        html.option( { "value":i['id']},i['choice_text'])
        for i in items_choices
      ])

   list_item_elements = [
      html.option( { "value":i['id']},i['question_text'])
      for i in items
   ]
   return html.div (
     html.select({"on_change": handle_click },list_item_elements),
     html.select({"on_change": handle_choices },choices),
     html.div(resposta)
   ) 

@component
def HelloWorld():
    response_API = requests.get('http://localhost:8002/api/get_questions')
    resultat = response_API.json()
    questions =  resultat['questions']
    # for parcial in resultat:
    #    print(parcial['question_text'])
    for parcial in questions:
        print(parcial['question_text'])

    return html._(
      html.h1("Llista de tasques ! "),
      html.div(Todos(questions)),

      html.ul(
        Item("Aprendre React amb Python", True),
        Item("Dominar Django com un pro"),
        Item("Sobreviure a un projecte amb Laravel")
        
      )
    )

app = FastAPI()
configure (app, HelloWorld )