Las aplicaciones de React se construyen a partir de piezas independientes de UI llamadas componentes.
Introducción
Un componente de React es una función de TypeScript a la que le puedes agregar TSX.
Crea un proyecto con Bun
$ bun create vite react-component --template react-swc-ts
Scaffolding project in /home/box/react-component...
...
Componente
Define el componente Greeting
que es utilitzado por el componente App
:
export default function App() {
return <Greeting/>
}
function Greeting() {
return <p className="fs-3 p-4 border">Hello X</p>
}
¡Los componentes de React son funciones regulares de TypeScript, pero sus nombres deben comenzar con letra mayúscula o no funcionarán!
El componente Greeting
està aninado dentro de el component App
.
Puedes añadir tantos componentes Greeting
com quieras dentro de el componente App
:
export default function App() {
return (
<>
<Greeting />
<Greeting />
<Greeting />
</>
)
}
function Greeting() {
return <p className="fs-3 m-2 p-2 border text-center">Hello X</p>
}
Al final lo que el navegador ve es esto:
<p class="fs-3 m-2 p-2 border text-center">Hello X</p>
<p class="fs-3 m-2 p-2 border text-center">Hello X</p>
<p class="fs-3 m-2 p-2 border text-center">Hello X</p>
Anidar y organizar componentes
Los componentes son funciones regulares de TypeScript, por lo que puedes tener múltiples componentes en el mismo archivo.
Dado que los componentes Greeting
se renderizan dentro de App
(¡incluso varias veces!) podemos decir que App
es un componente padre, que renderiza cada Greeting
como un «hijo».
Esta es la parte mágica de React: puedes definir un componente una vez, y luego usarlo en muchos lugares y tantas veces como quieras.
⚠ Atención!
Los componentes pueden renderizar otros componentes, pero nunca debes anidar sus definiciones:
export default function App() {
// 🔴 ¡Nunca definas un componente dentro de otro componente!
function Greeting() {
// ...
}
// ...
}
El fragmento de código de arriba es muy lento y causa errores.
En su lugar, define cada componente en el primer nivel:
export default function App() {
// ...
}
// ✅ Declara los componentes en el primer nivel
function Greeting() {
// ...
}
Propiedades
Los componentes de React utilizan props para comunicarse entre sí. Cada componente padre puede enviar información a sus componentes hijos mediante el uso de props.
Las props son los datos que se pasan a un elemento TSX.
Por ejemplo, className
, src
y alt
son algunas de las props que se pueden pasar a un elemento <img/>
:
export default function App() {
return (
<>
<img
className="img-fluid"
src="https://shorturl.at/tQoUY"
alt="Rough Collie"
/>
</>
)
}
Las props que puedes utilizar con una elemento <img/>
están predefinidas (ReactDOM se ajusta al estándar HTML).
Sin embargo, puedes pasar cualquier prop a tus propios componentes para personalizarlos.
Pasar props a un componente
En este código, el componente App
no está pasando ninguna prop a su componente hijo, Greeting
:
export default function App() {
return <Greeting/>
}
function Greeting() {
return <p className="fs-3 p-2"><span className="fs-1">🧔</span> Hello David!</p>
}
🧔 Hello David!
Lo lógico sería que el componente padre pasara al componente hijo el nombre i el emoji.
Primero, pasa las props name
y emoji
al elemento Greeting
.
export default function App() {
return <Greeting name="Laura" emoji="👩🦰"/>
}
El componente Greeting
a estas props especificando sus nombres name
y emoji
separados por comas dentro de ({
y })
:
function Greeting({name, emoji}: { name: string, emoji: string }) {
return <p className="fs-3 p-2"><span className="fs-1">{emoji}</span> Hello {name}!</p>
}
Ahora el componente Greeting
puede saludar correctamente:
👩🦰 Hello Laura!
Las props cumplen el mismo papel que los argumentos de una función — de hecho, ¡las props son el único argumento de tu componente!
Las funciones de los componentes de React aceptan un único argumento, un objeto props
:
function Greeting(props: { name: string, emoji: string }) {
return <p className="fs-3 p-2"><span className="fs-1">{props.emoji}</span> Hello {props.name}!</p>
}
En general, no necesitas acceder al objeto completo de props
, por lo que puedes desestructurarlo en props individuales;
function Greeting({name, emoji}: { name: string, emoji: string }) {
...
}
Esta sintaxis se conoce como "desestructuración".
Asignar un valor predeterminado para una prop
Si quieres asignar un valor predeterminado para una prop en caso de que no se especifique ningún valor, puedes hacerlo mediante la desestructuración colocando =
seguido del valor predeterminado justo después del parámetro:
function Greeting({name, emoji = "👽"}: { name: string, emoji?: string }) {
return <p className="fs-3 p-2"><span className="fs-1">{emoji}</span> Hello {name}!</p>
}
Fíjate que ahora el tipo de props és { name: string, emoji?: string }
, emoji és opcional.
Ahora, si renderizas Greeting
sin la prop emoji
, el valor de emoji
se establecerá automáticamente en "👽"
.
export default function App() {
return <Greeting name="Armengol"/>
}
👽 Hello Armengol!
Y ya tienes un componente completament reutilizable:
export default function App() {
return (
<>
<Greeting name="Miquel" emoji="🧙♂️"/>
<Greeting name="Armengol"/>
<Greeting name="Nuria" emoji="🐱"/>
</>
)
}
🧙♂️ Hello Miquel!
👽 Hello Armengol!
🐱 Hello Nuria!
Renderización
Una aplicación de React está formada por muchos componentes anidados entre sí.
React, como framework de UI, es independiente de la plataforma, y una aplicación React se puede renderizar en la web, la cual utiliza marcado HTML como sus primitivas, o podría renderizarse en una plataforma móvil o de escritorio, que podría utilizar diferentes primitivas de UI
Estructura de árbol
Al igual que los navegadores y las plataformas móviles, React utiliza estructuras de árbol para gestionar y modelar la relación entre los componentes en una aplicación de React.
Una característica importante de los componentes es la capacidad de componer componentes de otros componentes. Al anidar componentes, tenemos el concepto de componentes padre e hijo, donde cada componente padre puede ser a su vez un hijo de otro componente.
flowchart a([App]) g1([Greeting]) g2([Greeting]) g3([Greeting]) a --> g1 a --> g2 a --> g3 style a fill:#00f style g1 fill:#080 style g2 fill:#080 style g3 fill:#080
Cuando renderizamos una aplicación de React, podemos modelar esta relación en un árbol, conocido como el árbol de renderizado.
El nodo raíz en un árbol de renderizado de React es el componente raíz de la aplicación. En este caso, el componente raíz es App
y es el primer componente que React renderiza. Cada flecha en el árbol apunta desde un componente padre hacia un componente hijo.
- El árbol de renderizado está compuesto únicamente por componentes de React.
- Un árbol de renderizado representa un único pase de renderizado de una aplicación de React.
- Con renderizado condicional, un componente padre puede renderizar diferentes hijos dependiendo de los datos pasados.
- El árbol de renderizado puede ser diferente para cada pase de renderizado.
Componentes puros
React está diseñado con la suposición de que cada componente que escribes es una función pura.
Esto significa que un componente siempre debe devolver *el mismo TSX dadas las mismas entradas, y no cambiar cualquier objeto o variable que existiera antes de renderizar.
A continuación tienes un componente que rompe esta regla:
let evil = "🤗"
export default function App() {
return (
<div className="container">
<Greeting name="Miquel" emoji="🧙♂️"/>
<Greeting name="Armengol"/>
<Greeting name="Nuria" emoji="🐱"/>
</div>
)
}
function Greeting({name, emoji = "👽"}: { name: string, emoji?: string }) {
evil = `${evil} ${emoji}`
return <p className="fs-4 p-2"><span className="fs-2">{evil}</span> Hello {name}!</p>
}
Puedes ver que los emojis aparecen duplicados:
🤗 🧙♂️ 🧙♂️ Hello Miquel!
🤗 🧙♂️ 🧙♂️ 👽 👽 Hello Armengol!
🤗 🧙♂️ 🧙♂️ 👽 👽 🐱 🐱 Hello Nuria!
Y más importante, si cambias el orden de los Greeting
, devuelven un TSX diferente:
export default function App() {
return (
<div className="container">
<Greeting name="Nuria" emoji="🐱"/>
<Greeting name="Miquel" emoji="🧙♂️"/>
<Greeting name="Armengol"/>
</div>
)
}
🤗 🐱 🐱 Hello Nuria!
🤗 🐱 🐱 🧙♂️ 🧙♂️ Hello Miquel!
🤗 🐱 🐱 🧙♂️ 🧙♂️ 👽 👽 Hello Armengol!
Importar y exportar componentes
La magia de los componentes reside en su reusabilidad: puedes crear componentes que se componen a su vez de otros componentes.
Pero mientras anidas más y más componentes, a menudo tiene sentido comenzar a separarlos en diferentes archivos.
Crea un fichero src/Greeting.tsx
:
export default function Greeting({name, emoji = "👽"}: { name: string, emoji?: string }) {
return <p className="fs-4 p-2"><span className="fs-2">{emoji}</span> Hello {name}!</p>
}
Importa Greeting
con un import por defecto desde Greeting.tsx
:
import Greeting from './Greeting.tsx'
export default function App() {
return (
<div className="container">
<Greeting name="Nuria" emoji="🐱"/>
<Greeting name="Armengol"/>
</div>
)
}
Si quieres puedes canviar el nombre del componente cuando lo utilizas:
import Saluto from './Greeting.tsx'
export default function App() {
return (
<div className="container">
<Saluto name="Nuria" emoji="🐱"/>
<Saluto name="Armengol"/>
</div>
)
}
En lugar de utilizar un export por defecto puedes utilitzar un export por nombre (sin la palabra clave default
):
export function Greeting({name, emoji = "👽"}: { name: string, emoji?: string }) {
return <p className="fs-4 p-2"><span className="fs-2">{emoji}</span> Hello {name}!</p>
}
Ahora tienes que importar el componente Greeting
usando un import con nombre (con llaves):
import {Greeting} from './Greeting.tsx'
export default function App() {
return (
<div className="container">
<Greeting name="Nuria" emoji="🐱"/>
<Greeting name="Armengol"/>
</div>
)
}
¡Un archivo solo puede contener un export por defecto, pero puede tener múltiples exports con nombre!
Librerias
Hay muchas librerías de react que puedes utilizar: Awesome React Components.
Pigeon Maps - Docs te proporciona un componente que te permite añadir mapas sin dependencias externas.
Instala la librería pigeon-maps
:
bun add pigeon-maps
A continuación tenemos un mapa de Barcelona (Spain) con un marcador en la Sagrada Familia.
import {Map, Marker} from "pigeon-maps"
export default function App() {
return (
<div className="container p-5">
<Map height={600} defaultCenter={[41.40369, 2.17433]} defaultZoom={14}>
<Marker width={50} anchor={[41.40369, 2.17433]}/>
</Map>
</div>
)
}
Actividades
1.- DogCard
- Crea un componente
DogCard
con las propiedadesname
,description
eimage?
. - La propiedad
image?
tiene una imagen por defecto - Utiliza este componente para mostrar una colección de perros.

Rough Collie
A dog breed that's well-known for herding and protecting abilities, rough collie dogs are described as strong, loyal, affectionate, responsive, and fast.

Affenpinscher
Affenpinscher dogs are best known for their expressive face, with a short muzzle and dark, round eyes that give them an appearance not unlike a monkey.
export default function App() {
return (
<div className="container">
<div className="row p-2 justify-content-evenly">
<div className={"col-3"}>
<DogCard
name="Rough Collie"
description="A dog breed that's well-known for herding and protecting abilities, rough collie dogs are described as strong, loyal, affectionate, responsive, and fast."
image="https://upload.wikimedia.org/wikipedia/commons/thumb/6/65/Rough-Collie-japan08_%28cropped%29.jpg/1200px-Rough-Collie-japan08_%28cropped%29.jpg"/>
</div>
<div className="col-3">
<DogCard name="Affenpinscher"
description="Affenpinscher dogs are best known for their expressive face, with a short muzzle and dark, round eyes that give them an appearance not unlike a monkey."/>
</div>
</div>
</div>
)
}
function DogCard({name, description, image = "https://d29fhpw069ctt2.cloudfront.net/icon/image/39024/preview.png"}: {
name: string,
description: string,
image?: string
}) {
return (
<div className="card">
<img className="card-img-top img-fluid"
src={image}
alt={name}/>
<div className="card-body">
<h5 className="card-title">{name}</h5>
<p className="card-text">{description}</p>
</div>
</div>
)
}
2.- Happy.tsx
- Crea el fichero
Happy.tsx
con dos funciones con nombre:HappyName
yHappyImage
. HappyName
tiene una propiedadname
y muestra el nombre de forma divertida.HappyImage
tiene una propiedadimage
y muestra la imagen de forma divertida.- El componente
App
tiene que utilizar los dos componentes deHappy.tsx

App.tsx
import {HappyName,HappyImage} from "./Happy.tsx";
export default function App() {
return (
<div className="container p-5">
<HappyName name="Laura"/>
<HappyImage image="https://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Laura_Dern_Deauville_2017.jpg/440px-Laura_Dern_Deauville_2017.jpg"/>
</div>
)
}
Happy.tsx
export function HappyName({name}: { name: string }) {
return <span
className={"fs-3 border border-5 border-danger rounded-pill m-2 p-2 ps-5 pe-5 fw-semibold font-monospace"}>{name}</span>
}
export function HappyImage({image}: { image: string }) {
return <img src={image} className={"img-fluid img-thumbnail w-25 p-2 border border-5 border-primary"}/>
}
3.- Pigeon Maps
- Busca en Internet las coordendas geográficas y un GeoJSON de París.
- Crea un mapa de París y alrededores marcando los límites de París.
import {GeoJson,Map, ZoomControl} from "pigeon-maps"
export default function App() {
const data = {"type":"FeatureCollection","features":[{"type":"Feature","properties":{"name":"Bourse","cartodb_id":2,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:36:18.682Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.339999,48.87196],[2.34789,48.870689],[2.35433,48.869308],[2.350979,48.863411],[2.330292,48.868294],[2.328211,48.86972],[2.328072,48.869923],[2.339999,48.87196]]]]}},{"type":"Feature","properties":{"name":"Temple","cartodb_id":3,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:36:24.060Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.36236,48.867905],[2.364764,48.866436],[2.366694,48.86319],[2.368454,48.85582],[2.364335,48.856441],[2.361631,48.857262],[2.358626,48.858757],[2.356825,48.860111],[2.353391,48.861214],[2.350172,48.862034],[2.354249,48.869286],[2.36236,48.867905]]]]}},{"type":"Feature","properties":{"name":"Panthéon","cartodb_id":5,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:36:34.699Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.351799,48.83675],[2.345489,48.837601],[2.336462,48.839622],[2.342576,48.850258],[2.344199,48.85376],[2.3445,48.854038],[2.346859,48.853298],[2.350169,48.851997],[2.3548,48.850788],[2.36098,48.84861],[2.366,48.844997],[2.36493,48.844379],[2.361839,48.84],[2.351799,48.83675]]]]}},{"type":"Feature","properties":{"name":"Luxembourg","cartodb_id":6,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:36:40.774Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.316469,48.846851],[2.31904,48.847851],[2.32412,48.850311],[2.32704,48.851608],[2.32866,48.851952],[2.331599,48.856339],[2.33386,48.85918],[2.337499,48.85849],[2.340592,48.85675],[2.342512,48.855247],[2.344465,48.853992],[2.34425,48.853767],[2.342639,48.850349],[2.33652,48.83963],[2.31999,48.8451],[2.316469,48.846851]]]]}},{"type":"Feature","properties":{"name":"Palais-Bourbon","cartodb_id":7,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:36:45.091Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.309531,48.84581],[2.307342,48.847153],[2.289877,48.858192],[2.294769,48.861862],[2.300219,48.863499],[2.31833,48.863838],[2.331462,48.859676],[2.333844,48.85918],[2.33159,48.856258],[2.33041,48.854424],[2.329295,48.852673],[2.328479,48.851826],[2.327106,48.851601],[2.319274,48.847801],[2.313651,48.845909],[2.311355,48.845215],[2.309531,48.84581]]]]}},{"type":"Feature","properties":{"name":"Élysée","cartodb_id":8,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:36:51.084Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.30155,48.864601],[2.299869,48.865131],[2.298799,48.86869],[2.297299,48.871151],[2.295539,48.87326],[2.29457,48.873192],[2.294029,48.873669],[2.294399,48.87429],[2.295409,48.874317],[2.297769,48.87775],[2.297639,48.878029],[2.298049,48.87846],[2.298799,48.87825],[2.309009,48.880459],[2.316609,48.88134],[2.32721,48.88345],[2.326849,48.875908],[2.326611,48.875404],[2.326976,48.873825],[2.326869,48.873329],[2.32629,48.872597],[2.326505,48.872471],[2.325819,48.869534],[2.325152,48.869392],[2.32526,48.869019],[2.320769,48.863098],[2.31828,48.863811],[2.30167,48.863522],[2.30155,48.864601]]]]}},{"type":"Feature","properties":{"name":"Opéra","cartodb_id":9,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:37:00.221Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.339599,48.882011],[2.34952,48.883781],[2.34987,48.880692],[2.349209,48.87888],[2.349,48.87722],[2.348139,48.87566],[2.34785,48.873871],[2.34789,48.870689],[2.34004,48.87196],[2.32579,48.869572],[2.326519,48.872471],[2.326309,48.872589],[2.32688,48.873341],[2.326979,48.873779],[2.32663,48.875439],[2.32682,48.87595],[2.32717,48.883419],[2.327929,48.883621],[2.32948,48.884651],[2.337406,48.882271],[2.339599,48.882011]]]]}},{"type":"Feature","properties":{"name":"Enclos-St-Laurent","cartodb_id":10,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:37:05.756Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.368755,48.884079],[2.369142,48.883289],[2.370213,48.882637],[2.370257,48.878632],[2.370814,48.878124],[2.370601,48.87756],[2.376952,48.872108],[2.372917,48.870644],[2.364205,48.86779],[2.363477,48.867226],[2.362404,48.867905],[2.354293,48.869286],[2.347941,48.870728],[2.347812,48.873943],[2.348155,48.875751],[2.348971,48.877277],[2.349272,48.879223],[2.349873,48.880692],[2.349486,48.883797],[2.359227,48.884472],[2.364806,48.884361],[2.368755,48.884079]]]]}},{"type":"Feature","properties":{"name":"Popincourt","cartodb_id":11,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:37:14.753Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.383175,48.867115],[2.383776,48.86607],[2.387465,48.862823],[2.389654,48.858444],[2.39223,48.857571],[2.394321,48.856548],[2.398398,48.85133],[2.399214,48.848709],[2.399064,48.848103],[2.395899,48.848351],[2.384291,48.85017],[2.379999,48.850483],[2.371544,48.852459],[2.370257,48.853222],[2.369184,48.853081],[2.366737,48.86319],[2.36472,48.866409],[2.363477,48.867256],[2.364205,48.86779],[2.376866,48.872108],[2.383175,48.867115]]]]}},{"type":"Feature","properties":{"name":"Gobelins","cartodb_id":13,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:37:25.726Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.342039,48.838322],[2.345431,48.837605],[2.348927,48.837067],[2.35189,48.836731],[2.36193,48.840031],[2.36493,48.844379],[2.365959,48.844997],[2.38856,48.826481],[2.385269,48.825298],[2.37881,48.82148],[2.363339,48.816132],[2.356799,48.816441],[2.3544,48.817501],[2.351669,48.817989],[2.346839,48.81641],[2.34405,48.816441],[2.3441,48.817631],[2.34459,48.819382],[2.343939,48.820278],[2.34242,48.821461],[2.34146,48.823658],[2.34165,48.826408],[2.34131,48.831429],[2.34111,48.831947],[2.342039,48.838322]]]]}},{"type":"Feature","properties":{"name":"Observatoire","cartodb_id":14,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:37:30.531Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.301464,48.825428],[2.321032,48.841503],[2.321547,48.840996],[2.324594,48.843651],[2.336396,48.839695],[2.342105,48.838284],[2.341117,48.831982],[2.341504,48.828793],[2.341632,48.8256],[2.341504,48.823254],[2.34249,48.821304],[2.344036,48.820118],[2.344551,48.819355],[2.344164,48.817574],[2.344078,48.816502],[2.33571,48.816811],[2.332878,48.818478],[2.301464,48.825428]]]]}},{"type":"Feature","properties":{"name":"Vaugirard","cartodb_id":15,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:37:35.322Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.292365,48.827492],[2.277001,48.833763],[2.274255,48.830429],[2.275027,48.829807],[2.272797,48.82896],[2.270564,48.828114],[2.267818,48.828171],[2.267303,48.831108],[2.27065,48.833591],[2.269191,48.835342],[2.266188,48.834724],[2.264127,48.835175],[2.278204,48.849014],[2.287644,48.855679],[2.289963,48.858276],[2.309274,48.845852],[2.311335,48.845287],[2.316483,48.846813],[2.320003,48.845173],[2.324552,48.843594],[2.321633,48.841049],[2.320948,48.841618],[2.301464,48.825512],[2.292365,48.827492]]]]}},{"type":"Feature","properties":{"name":"Passy","cartodb_id":16,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:37:40.880Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.28007,48.878292],[2.294939,48.873859],[2.297387,48.871193],[2.299039,48.868427],[2.29991,48.865269],[2.301571,48.864574],[2.3018,48.863361],[2.29408,48.86166],[2.28893,48.85759],[2.28601,48.854321],[2.277429,48.847988],[2.26404,48.835121],[2.257859,48.835678],[2.253909,48.839298],[2.25477,48.845398],[2.2503,48.845509],[2.241719,48.848328],[2.2273,48.84856],[2.225929,48.85545],[2.23159,48.86652],[2.23932,48.870468],[2.2467,48.876339],[2.25511,48.874199],[2.258199,48.88052],[2.28007,48.878292]]]]}},{"type":"Feature","properties":{"name":"Batignolles-Monceau","cartodb_id":17,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:37:46.239Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.27999,48.878361],[2.28325,48.882771],[2.29185,48.88842],[2.29768,48.889648],[2.306185,48.895111],[2.314081,48.898159],[2.32188,48.900612],[2.33013,48.900799],[2.32562,48.887589],[2.32721,48.88345],[2.31691,48.881302],[2.30867,48.880402],[2.29807,48.878151],[2.29502,48.873909],[2.27999,48.878361]]]]}},{"type":"Feature","properties":{"name":"Butte-Montmartre","cartodb_id":18,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:37:52.398Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.370379,48.900719],[2.370379,48.896709],[2.37184,48.895359],[2.370289,48.894459],[2.367081,48.887592],[2.36663,48.886604],[2.36472,48.884411],[2.358789,48.884411],[2.34952,48.883678],[2.339739,48.88187],[2.337254,48.882286],[2.32953,48.88443],[2.32792,48.883526],[2.327192,48.883415],[2.325603,48.887619],[2.33021,48.900829],[2.353209,48.901279],[2.370379,48.900719]]]]}},{"type":"Feature","properties":{"name":"Buttes-Chaumont","cartodb_id":19,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:37:58.058Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.408749,48.877857],[2.402309,48.875999],[2.395255,48.875259],[2.39021,48.875549],[2.387719,48.874531],[2.386519,48.874649],[2.38472,48.873859],[2.376819,48.872219],[2.370379,48.87809],[2.37021,48.882771],[2.36892,48.883339],[2.368669,48.884132],[2.364742,48.884403],[2.366781,48.886688],[2.368348,48.890202],[2.370289,48.894508],[2.37175,48.89547],[2.370279,48.896648],[2.370379,48.90078],[2.3769,48.900269],[2.38849,48.900661],[2.392009,48.899818],[2.39381,48.898239],[2.39725,48.88588],[2.401879,48.88176],[2.4066,48.880119],[2.408749,48.877857]]]]}},{"type":"Feature","properties":{"name":"Louvre","cartodb_id":1,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:36:13.177Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.320769,48.863037],[2.325229,48.868938],[2.325149,48.869419],[2.328018,48.869949],[2.330302,48.868286],[2.350944,48.863407],[2.347351,48.857124],[2.34691,48.856972],[2.345966,48.855373],[2.344529,48.854012],[2.3424,48.855247],[2.340469,48.8568],[2.33725,48.858467],[2.331459,48.85968],[2.320769,48.863037]]]]}},{"type":"Feature","properties":{"name":"Hôtel-de-Ville","cartodb_id":4,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:36:29.259Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.36465,48.845989],[2.360899,48.84864],[2.35467,48.850849],[2.35013,48.851978],[2.34695,48.853298],[2.344551,48.854027],[2.345966,48.855396],[2.346986,48.856964],[2.347329,48.857147],[2.350169,48.86203],[2.353299,48.86124],[2.35678,48.860161],[2.358579,48.858749],[2.36167,48.857258],[2.364329,48.856407],[2.36836,48.855869],[2.3692,48.85281],[2.366299,48.846958],[2.36465,48.845989]]]]}},{"type":"Feature","properties":{"name":"Reuilly","cartodb_id":12,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:37:20.571Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.414499,48.846809],[2.41252,48.836529],[2.409609,48.83427],[2.41407,48.833698],[2.42214,48.83585],[2.420249,48.840588],[2.419299,48.84206],[2.419989,48.84359],[2.42179,48.844547],[2.42445,48.841778],[2.438359,48.840588],[2.43922,48.844547],[2.44085,48.84444],[2.44076,48.845959],[2.4466,48.845901],[2.44634,48.84494],[2.455519,48.844097],[2.46334,48.842232],[2.46977,48.836529],[2.46909,48.834148],[2.465219,48.831497],[2.46428,48.827599],[2.466,48.827259],[2.464789,48.822968],[2.462559,48.819458],[2.45887,48.81715],[2.453889,48.816978],[2.44857,48.818157],[2.4375,48.818439],[2.43733,48.81963],[2.431919,48.822628],[2.42763,48.82415],[2.421959,48.824211],[2.419729,48.8241],[2.41733,48.8246],[2.41107,48.825001],[2.40669,48.826981],[2.403509,48.8293],[2.40111,48.829689],[2.39562,48.828049],[2.390719,48.827198],[2.38858,48.826469],[2.364539,48.84613],[2.366429,48.847031],[2.36918,48.85313],[2.370379,48.85313],[2.371544,48.852417],[2.38017,48.850368],[2.384459,48.850079],[2.39596,48.848328],[2.414499,48.846809]]]]}},{"type":"Feature","properties":{"name":"Ménilmontant","cartodb_id":20,"created_at":"2013-02-26T07:07:16.384Z","updated_at":"2013-02-26T18:38:05.143Z"},"geometry":{"type":"MultiPolygon","coordinates":[[[[2.4133,48.865269],[2.41414,48.859051],[2.41398,48.853809],[2.414675,48.852573],[2.41527,48.851028],[2.41441,48.846802],[2.39904,48.848099],[2.3993,48.848789],[2.39835,48.851261],[2.39441,48.856522],[2.38965,48.858471],[2.38737,48.862961],[2.3835,48.866169],[2.38319,48.867142],[2.37682,48.872231],[2.38497,48.873959],[2.38651,48.874691],[2.38789,48.874531],[2.39037,48.875542],[2.39529,48.87521],[2.40221,48.87595],[2.40858,48.87785],[2.41097,48.87431],[2.41338,48.87109],[2.4133,48.865269]]]]}}]}
return (
<div className="container p-5">
<Map height={600} defaultCenter={[48.85341, 2.3488]} defaultZoom={12}>
<ZoomControl/>
<GeoJson data={data}/>
</Map>
</div>
)
}
4.- Plotly
Plotly es una librería que te permite crear gráficos interactivos.
En la actividad Plotly aprenderás a utilizar la librería.
Importa plotly:
$ bun add plotly.js react-plotly.js
$ bun add --dev @types/plotly.js @types/react-plotly.js
Crea un gráfico de lineas:
import Plot from 'react-plotly.js'
export default function App() {
const data = [
{
x: [1, 2, 3, 4],
y: [100, 35, 200, 90],
mode: "lines",
},
];
const layout = { title: "Chart Title" };
return <Plot data={data} layout={layout} />;
}
Modifica el gráfico.