TSX és una extensió sintàctica per Typescript que et permet escriure codi que s'assembla a HTML dins d'un fitxer Typescript
Introducció
TSX s'assembla molt al HTML, però és més estricte i pot mostrar informació dinàmica.
Et permet tenir en el mateix lloc el contingut i la lògica de renderització.
Recursos:
-
El projecte de suport està a https://gitlab.com/xtec/typescript/react-tsx
-
La pàgina web està a https://react-tsx-8cc692.gitlab.io/.
Entorn de treball
Instal.la Bun
Crea un projecte amb Vite
$ bun create vite tsx --template react-swc-ts
Scaffolding project in /home/box/game...
Done. Now run:
cd tsx
bun install
bun run dev
Executa les instruccions ... i obre el navegador: http://localhost:5173/
A continuació configura el projecte:
- Afegeix la llibreria bootstrap a
index.html
<link rel="stylesheet" href=" https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css"/>
-
Elimina els fitxers
index.css
iApp.css
-
Elimina l'import del fitxer
index.css
demain.tsx
. -
Modifica el contingut del fitxer
App.tsx
.
export default function App() {
return <h1>Hello</h1>
}
El prefixe export default
és part de la sintaxis estàndard de Typescript (no és específic de React).
Et permet marcar la funció principal d'un arxiu perquè després la puguis importar en altres arxius.
Regles
A continuació veurem les regles TSX.
Només pots retornar un únic element arrel
export default function App() {
return (
<h1>Alí Bey</h1>
<p>Aquesta és la història</p>
)
}
Si has de retornar més d'un element, els has d'afegir tots dins d'un element arrel.
Per exemple, pots utilitzar un <div>
:
export default function App() {
return (
<div>
<h1>Alí Bey</h1>
<p>Aquesta és la història ...</p>
</div>
)
}
Una altra opció és utilitzar l'element buit <>
:
export default function App() {
return (
<>
<h1>Alí Bey</h1>
<p>Aquesta és la història ...</p>
</>
)
}
Aquest element és invisible i no genera cap element de marcatge.
export default function App() {
return (
<>
<h1>Alí Bey</h1>
<p>Aquesta és la història ...</p>
</>
)
}
Tanca tots els tags
Totes les "etiquetes" TSX s'ahn de tancar de manera explícita.
En aquest exemple tens una etiquet <img>
que no està tancada:
export default function App() {
return (
<img src="https://upload.wikimedia.org/wikipedia/commons/4/48/Rough_Collie_600.jpg">
)
}
L'has de tancar de manera explícita:
export default function App() {
return (
<img src="https://upload.wikimedia.org/wikipedia/commons/4/48/Rough_Collie_600.jpg"/>
)
}
camelCase
TSX és converteix en Typescript, i els atributs dels elements TSX es converteixen en atributs d'objectes TypeScript.
Per tant, els noms dels atributs TSX estan limitats pels noms que poden tenir els atributs d'objecte Typescript.
Per exemple, els noms no poden tenir guions no utilitzar paraules reservades com class
.
export default function App() {
return (
<div class="container">
<img src="https://upload.wikimedia.org/wikipedia/commons/4/48/Rough_Collie_600.jpg"/>
</div>
)
}
Com que class
és una paraula reservada, has d'utilitzar className
, el nom de la propietat que correspon al DOM:
export default function App() {
return (
<div className="container">
<img src="https://upload.wikimedia.org/wikipedia/commons/4/48/Rough_Collie_600.jpg"/>
</div>
)
}
Pots trobar tots aquests atributs a la llista de propietats de component del DOM.
Typescript dins de TSX
Amb la clau {}
pots afegir referenciar una propietat dinàmica dins del "markup":
export default function App() {
const radius = 5
const area = 3.141592653 * (radius ** 2)
return (
<div className="container m-5">
<p>Area of {radius} is {area}</p>
</div>
)
}
També pots afegir codi Typescript directament codi:
export default function App() {
return (
<div className="container m-5">
<p>Area of 9 is {3.141592653 * (9 ** 2)}</p>
</div>
)
}
Això també inclou el cridar funcions:
export default function App() {
function area(radius: number) {
return 3.141592653 * (radius ** 2)
}
return (
<div className="container m-5">
<p>Area of 5 is {area(5)}</p>
</div>
)
}
Debugger
Pots utilitzar la instrucció debugger
per analitzar el codi en execució.
Per exemple:
export default function App() {
const radius = 7
debugger
const PI = 3.141592653
const area = PI * (radius ** 2)
return (
<div className="container m-5">
<p>Area of 5 is {area}</p>
</div>
)
}
- Obre la pàgina amb el navegador "Google Chrome": http://localhost:5173/
- Obre l'eina per desenvolupadors del navegador amb
Ctrl+Shift+I
. - Refresca la pàgina
F5
Renderitzat condicional
Pots utilitzar la sentència if
per controlar quin arbre TSX es tornarà en funció d'una condició:
export default function App() {
const age = 17
if (age < 18) {
return (
<div className="container m-5">
<p className="text-warning">Encara ets massa jove per entrar al club de les tortugues</p>
</div>
)
}
return (
<div className="container m-5">
<p>Benvigut al club 🐢🐢🐢 !</p>
</div>
)
}
En aquest exemple pots veure que una part del contingut està duplicat.
Si vols pots utilitzar l'operador ? :
dins una clau {}
per eliminar codi duplicat:
export default function App() {
const age = 17
return (
<div className="container m-5 text-center">
<p className="fs-1 m-2">🐢</p>
{ age < 18 ?
<p className="text-warning">Encara ets massa jove per entrar al club de les tortugues</p> :
<p>Benvigut al club 🐢🐢🐢 !</p>
}
</div>
)
}
També pots utilitzar l'operador &&
per generar contingut només si es dona una condició:
export default function App() {
const age = 120
return (
<div className="container m-5 text-center">
<p className="fs-1 m-2">🐢</p>
{ age < 18 ?
<p className="text-warning">Encara ets massa jove per entrar al club de les tortugues</p> :
<p>Benvigut al club 🐢🐢🐢 !</p>
}
{ (age > 100) && <p className="fs-5 m-t 3">🌈 Ets una super tortuga!</p>}
</div>
)
}
Si vols pots guardar codi TSX en una variable:
// TODO
Llistes
Una situació habitual és que tinguis una llista, i vols mostrar tots (o alguns) elements de la llista.
Amb el mètode map()
pots transformar la llista en una llista d'elements TSX.
export default function App() {
const people = [
'Creola Katherine Johnson: mathematician',
'Mario José Molina-Pasquel Henríquez: chemist',
'Mohammad Abdus Salam: physicist',
'Percy Lavon Julian: chemist',
'Subrahmanyan Chandrasekhar: astrophysicist'
]
return (
<div className="container m-5">
<ul>
{people.map(person => <li>{person}</li>)}
</ul>
</div>
)
}
Si només vols mostrar aquelles persones que són químics, pots utilitzar el mètode filter()
per filtrar la llista:
export default function App() {
// ...
const chemists = people.filter(person => person.includes("chemist"))
return (
<div className="container m-5">
<ul>
{chemists.map(chemist => <li>{chemist}</li>)}
</ul>
</div>
)
}
Pàgina web
React et permet construir aplicacions web client.
Obre el terminal i executa:
> bun run build
vite v6.0.3 building for production...
✓ 26 modules transformed.
dist/index.html 0.48 kB │ gzip: 0.32 kB
dist/assets/index-COkpbCJz.js 145.81 kB │ gzip: 47.24 kB
✓ built in 707ms
Ja pots pujar aquest fitxers a un lloc web.
Per exemple, amb Gitlab Pages: https://gitlab.com/xtec/typescript/react-tsx/-/blob/main/.gitlab-ci.yml?ref_type=heads
Activitat
1.- A continuació tens una llista de temperatures mitjes mensuals de l'aire de la ciutat de Barcelona des de l'any 2000.
Has de mostrar la informació en una taula:
export default function App() {
const tss = [
[2000, 7.7, 11.4, 12.6, 13.3, 18.3, 21, 22.8, 24.5, 21, 16, 11.3, 11],
[2001, 9.9, 10.1, 14.8, 13.8, 18.2, 21.9, 23.7, 25, 19.6, 19.4, 10.7, 6.8],
[2002, 9.2, 11.1, 12.3, 13.7, 15.5, 22.3, 22.9, 21.6, 19.9, 17.4, 13, 10.4],
[2003, 7.9, 7.1, 12.1, 14, 18, 25.6, 26.1, 28.5, 20.8, 15.2, 12.7, 8.8],
[2004, 9.4, 8.6, 10, 12.8, 16.2, 22.4, 23.5, 25.1, 21.4, 18.9, 11.4, 9.3],
[2005, 7.2, 6.5, 10.2, 14, 18.8, 23.4, 24.4, 23, 20.7, 17.9, 11.1, 6.6],
[2006, 7.4, 8.5, 12, 15.1, 18.7, 22.1, 27.1, 22.8, 21.6, 18.8, 14.6, 10],
[2007, 9.9, 11.4, 12.1, 15, 17.9, 22, 23.6, 22.5, 20.6, 16.4, 11.2, 8.8],
[2008, 10.1, 10.2, 10.8, 13.7, 16.6, 20.7, 23.8, 24.3, 20.7, 16.5, 10.3, 7.5],
[2009, 7.2, 8.7, 11.2, 13.1, 18.8, 23, 24.4, 26.3, 21.5, 17.9, 13.5, 9],
[2010, 6.6, 8, 9.6, 14.1, 15.4, 20.3, 25.7, 24.3, 20.9, 16.2, 11, 8.5],
[2011, 8.4, 10, 10.9, 15.9, 18.3, 19.5, 21.2, 24.1, 22.9, 19.1, 14.1, 10.2],
[2012, 9.4, 6.8, 13.4, 12.6, 17.9, 22.3, 23.2, 26, 21.4, 17.3, 12.7, 9.9],
[2013, 9.1, 7.7, 11.2, 13.5, 14.6, 19.5, 25.6, 24.9, 22.0, 19.5, 12.2, 10.1],
[2014, 9.8, 10.1, 12.3, 15.3, 16.2, 21.7, 22.6, 23, 22, 19.6, 13.6, 9.1],
[2015, 9.1, 8.2, 12, 14.8, 19.1, 23.2, 26.0, 23.50, 19.7, 16.7, 14.3, 12.6],
[2016, 10.7, 11.3, 11.1, 13.6, 16.4, 21.6, 24.9, 24.5, 22.3, 17.1, 12.7, 11.5],
[2017, 7.9, 11.4, 13.3, 14.2, 18.3, 23.6, 24.2, 24.5, 19.5, 18.6, 12.5, 8.5],
[2018, 10.5, 6.7, 10.8, 14.7, 17.1, 21.5, 25.3, 25.8, 22.5, 17.0, 12.4, 11.1],
[2019, 8.1, 11.9, 13.5, 13.4, 15.6, 21.9, 25.4, 25.1, 21.8, 18.5, 11.9, 11.2],
[2020, 10.0, 12.8, 11.9, 14.3, 19.4, 20.1, 25.0, 25.5, 21.7, 16.4, 14.7, 9.3],
[2021, 7.7, 11.6, 12.1, 12.9, 17.3, 23.3, 24.8, 24.5, 23.0, 18.1, 11.3, 10.9],
[2022, 10.2, 11.8, 10.8, 14.1, 20.7, 24.7, 26.7, 27.2, 22.5, 20.7, 15.2, 12.6],
[2023, 9.2, 10.3, 14.1, 16.1, 18.1, 23.4, 25.5, 26, 23.2, 20.2, 14.8, 12.1]
]
return <h1>Temperatures Barcelona</h1>
}
export default function App() {
// ...
const heads = ["Any", "Gener", "Febrer", "Març", "Abril", "Maig", "Juny", "Juliol",
"Agost", "Setembre", "Octubre", "Novembre", "Desembre"]
return (
<div className="container m-5">
<h1 className="text-center">Temperatures de Barcelona</h1>
<table className="table table-striped table-bordered mt-5">
<thead>
<tr className="table-primary">
{heads.map(head => <th scope="col">{head}</th>)}
</tr>
</thead>
<tbody>
{tss.map(ts => <tr>
<th scope="row" className="table-secondary">{ts[0]}</th>
{
ts.slice(1).map(t => <td>{t}</td>)
}</tr>)}
</tbody>
</table>
</div>
)
}
2.- A continuació has de posar color a les celes.
Mostra en:
- Color blau les temperatures inferiors a 10
- En color vermell les temperatures superiors a 20
export default function App() {
// ...
return (
<div className="container m-5">
<h1 className="text-center">Temperatures de Barcelona</h1>
<table className="table table-striped table-bordered mt-5">
<thead>
<tr className="table-primary">
{heads.map(head => <th scope="col">{head}</th>)}
</tr>
</thead>
<tbody>
{tss.map(ts => <tr>
<th scope="row" className="table-secondary">{ts[0]}</th>
{
ts.slice(1).map(t => t <10 ? <td className="table-info">{t}</td> :
t > 20 ? <td className="table-danger">{t}</td>: <td>{t}</td>)
}</tr>)}
</tbody>
</table>
</div>
)
}
Temperatures de Barcelona
Any | Gener | Febrer | Març | Abril | Maig | Juny | Juliol | Agost | Setembre | Octubre | Novembre | Desembre |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2000 | 7.7 | 11.4 | 12.6 | 13.3 | 18.3 | 21 | 22.8 | 24.5 | 21 | 16 | 11.3 | 11 |
2001 | 9.9 | 10.1 | 14.8 | 13.8 | 18.2 | 21.9 | 23.7 | 25 | 19.6 | 19.4 | 10.7 | 6.8 |
2002 | 9.2 | 11.1 | 12.3 | 13.7 | 15.5 | 22.3 | 22.9 | 21.6 | 19.9 | 17.4 | 13 | 10.4 |
2003 | 7.9 | 7.1 | 12.1 | 14 | 18 | 25.6 | 26.1 | 28.5 | 20.8 | 15.2 | 12.7 | 8.8 |
2004 | 9.4 | 8.6 | 10 | 12.8 | 16.2 | 22.4 | 23.5 | 25.1 | 21.4 | 18.9 | 11.4 | 9.3 |
2005 | 7.2 | 6.5 | 10.2 | 14 | 18.8 | 23.4 | 24.4 | 23 | 20.7 | 17.9 | 11.1 | 6.6 |
2006 | 7.4 | 8.5 | 12 | 15.1 | 18.7 | 22.1 | 27.1 | 22.8 | 21.6 | 18.8 | 14.6 | 10 |
2007 | 9.9 | 11.4 | 12.1 | 15 | 17.9 | 22 | 23.6 | 22.5 | 20.6 | 16.4 | 11.2 | 8.8 |
2008 | 10.1 | 10.2 | 10.8 | 13.7 | 16.6 | 20.7 | 23.8 | 24.3 | 20.7 | 16.5 | 10.3 | 7.5 |
2009 | 7.2 | 8.7 | 11.2 | 13.1 | 18.8 | 23 | 24.4 | 26.3 | 21.5 | 17.9 | 13.5 | 9 |
2010 | 6.6 | 8 | 9.6 | 14.1 | 15.4 | 20.3 | 25.7 | 24.3 | 20.9 | 16.2 | 11 | 8.5 |
2011 | 8.4 | 10 | 10.9 | 15.9 | 18.3 | 19.5 | 21.2 | 24.1 | 22.9 | 19.1 | 14.1 | 10.2 |
2012 | 9.4 | 6.8 | 13.4 | 12.6 | 17.9 | 22.3 | 23.2 | 26 | 21.4 | 17.3 | 12.7 | 9.9 |
2013 | 9.1 | 7.7 | 11.2 | 13.5 | 14.6 | 19.5 | 25.6 | 24.9 | 22 | 19.5 | 12.2 | 10.1 |
2014 | 9.8 | 10.1 | 12.3 | 15.3 | 16.2 | 21.7 | 22.6 | 23 | 22 | 19.6 | 13.6 | 9.1 |
2015 | 9.1 | 8.2 | 12 | 14.8 | 19.1 | 23.2 | 26 | 23.5 | 19.7 | 16.7 | 14.3 | 12.6 |
2016 | 10.7 | 11.3 | 11.1 | 13.6 | 16.4 | 21.6 | 24.9 | 24.5 | 22.3 | 17.1 | 12.7 | 11.5 |
2017 | 7.9 | 11.4 | 13.3 | 14.2 | 18.3 | 23.6 | 24.2 | 24.5 | 19.5 | 18.6 | 12.5 | 8.5 |
2018 | 10.5 | 6.7 | 10.8 | 14.7 | 17.1 | 21.5 | 25.3 | 25.8 | 22.5 | 17 | 12.4 | 11.1 |
2019 | 8.1 | 11.9 | 13.5 | 13.4 | 15.6 | 21.9 | 25.4 | 25.1 | 21.8 | 18.5 | 11.9 | 11.2 |
2020 | 10 | 12.8 | 11.9 | 14.3 | 19.4 | 20.1 | 25 | 25.5 | 21.7 | 16.4 | 14.7 | 9.3 |
2021 | 7.7 | 11.6 | 12.1 | 12.9 | 17.3 | 23.3 | 24.8 | 24.5 | 23 | 18.1 | 11.3 | 10.9 |
2022 | 10.2 | 11.8 | 10.8 | 14.1 | 20.7 | 24.7 | 26.7 | 27.2 | 22.5 | 20.7 | 15.2 | 12.6 |
2023 | 9.2 | 10.3 | 14.1 | 16.1 | 18.1 | 23.4 | 25.5 | 26 | 23.2 | 20.2 | 14.8 | 12.1 |