{"id":23701163,"url":"https://github.com/gitfrandu4/react-tutorial-tic-tac-toe","last_synced_at":"2026-01-27T23:03:15.624Z","repository":{"id":211625180,"uuid":"426581559","full_name":"gitfrandu4/react-tutorial-tic-tac-toe","owner":"gitfrandu4","description":"Repositorio tutorial sobre cómo construir un juego de tic-tac-toe interactivo con React.","archived":false,"fork":false,"pushed_at":"2021-11-10T10:52:46.000Z","size":221,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-22T21:13:59.040Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gitfrandu4.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-11-10T10:38:26.000Z","updated_at":"2021-11-10T10:52:49.000Z","dependencies_parsed_at":"2023-12-09T19:52:45.412Z","dependency_job_id":null,"html_url":"https://github.com/gitfrandu4/react-tutorial-tic-tac-toe","commit_stats":null,"previous_names":["gitfrandu4/react-tutorial-tic-tac-toe"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gitfrandu4/react-tutorial-tic-tac-toe","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitfrandu4%2Freact-tutorial-tic-tac-toe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitfrandu4%2Freact-tutorial-tic-tac-toe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitfrandu4%2Freact-tutorial-tic-tac-toe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitfrandu4%2Freact-tutorial-tic-tac-toe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gitfrandu4","download_url":"https://codeload.github.com/gitfrandu4/react-tutorial-tic-tac-toe/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitfrandu4%2Freact-tutorial-tic-tac-toe/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28826434,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T18:44:20.126Z","status":"ssl_error","status_checked_at":"2026-01-27T18:44:09.161Z","response_time":168,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-30T09:32:22.124Z","updated_at":"2026-01-27T23:03:15.587Z","avatar_url":"https://github.com/gitfrandu4.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tutorial: Introducción a React\n\n\u003e https://es.reactjs.org/tutorial/tutorial.html\n\n## Visión General\n\n**¿Qué es React?**\n\nReact es una librería de JavaScript declarativa, eficiente y flexible para construir interfaces de usuario. Permite componer IUs complejas de pequeñas y aisladas piezas de código llamadas “componentes”.\n\nReact tiene pocos tipos diferentes de componentes, pero vamos a empezar con la subclase React.Component:\n\n```javascript\nclass ShoppingList extends React.Component {\n  render() {\n    return (\n      \u003cdiv className=\"shopping-list\"\u003e\n        \u003ch1\u003eLista de compras para {this.props.name}\u003c/h1\u003e\n        \u003cul\u003e\n          \u003cli\u003eInstagram\u003c/li\u003e\n          \u003cli\u003eWhatsApp\u003c/li\u003e\n          \u003cli\u003eOculus\u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n\n// Uso de ejemplo: \u003cShoppingList name=\"Mark\" /\u003e\n```\n\nUsamos componentes para decirle a React lo que queremos que se vea en la pantalla. Cuando nuestros datos cambian, React actualizará eficientemente y volverá a renderizar (re-render) nuestros componentes.\n\nAquí, ShoppingList es una clase de componente de React, ó tipo de componente de React. Un componente acepta parámetros, llamados props (abreviatura de “propiedades”), y retorna una jerarquía de vistas a mostrar a través del método render.\n\nEl método render retorna una descripción de lo que quieres ver en la pantalla. React toma la descripción y muestra el resultado. En particular, render retorna un elemento de React, el cuál es una ligera descripción de lo que hay que renderizar. La mayoría de desarrolladores de React usan una sintaxis especial llamada “JSX” que facilita la escritura de estas estructuras. La sintaxis \u003cdiv /\u003e es transformada en tiempo de construcción a React.createElement('div'). El ejemplo anterior es equivalente a:\n\n```javascript\nreturn React.createElement('div', {className: 'shopping-list'},\n  React.createElement('h1', /* ... h1 children ... */),\n  React.createElement('ul', /* ... ul children ... */)\n);\n```\n\nJSX viene con todo el poder de JavaScript. Puedes poner cualquier expresión de JavaScript en el interior de las llaves dentro de JSX. Cada elemento de React es un objeto de JavaScript que puedes almacenar en una variable o pasar alrededor de tu programa.\n\nEl componente anterior ShoppingList solo renderiza componentes pre-construidos del DOM como `\u003cdiv /\u003e` y `\u003cli /\u003e`. Pero, también puedes componer y renderizar componentes personalizados de React. Por ejemplo, ahora podemos referirnos al listado de compras completo escribiendo `\u003cShoppingList /\u003e`. Cada componente de React está encapsulado y puede operar independientemente; esto te permite construir IUs complejas desde componentes simples.\n\n### Inspeccionando el código inicial\n\nInspeccionando el código, notarás que tenemos 3 componentes de React:\n\n* Square\n* Board\n* Game\n\nEl componente Square renderiza un simple \u003cbutton\u003e y el Board renderiza 9 cuadrados. El componente Game renderiza un table con valores de posición por defecto que modificaremos luego. Actualmente no hay componentes interactivos.\n\n### Pasando datos a través de props\n\nEn el método renderSquare de Board, cambia el código para pasar una prop llamada value al Square:\n\n```javascript\nclass Board extends React.Component {\n  renderSquare(i) {\n    return \u003cSquare value={i} /\u003e;\n  }\n}\n```\n\nCambia el método render de Square para mostrar ese valor, reemplazando {/* TODO */} con {this.props.value}:\n\n```javascript\nclass Square extends React.Component {\n  render() {\n    return (\n      \u003cbutton className=\"square\"\u003e\n        {this.props.value}\n      \u003c/button\u003e\n    );\n  }\n}\n```\n\n¡Felicidades! Acabas de “pasar una prop” de un componente padre Board a un componente hijo Square. Pasando props es cómo la información fluye en apps de React, de padres a hijos.\n\n### Haciendo un componente interactivo\n\nVamos a rellenar el componente de Square con una “X” cuando damos click en él. Primero, cambia la etiqueta button que es retornada del método render() del componente Square a esto:\n\n```javascript\nclass Square extends React.Component {\n render() {\n   return (\n     \u003cbutton className=\"square\" onClick={() =\u003e console.log('click')}\u003e\n       {this.props.value}\n     \u003c/button\u003e\n   );\n }\n}\n```\n\n\u003e Para continuar escribiendo código sin problemas y evitar el confuso comportamiento de this, vamos a usar la sintaxis de funciones flecha para manejar eventos aquí y más abajo\n\u003e Ten en cuenta cómo con `onClick={() =\u003e console.log('click')}`, estamos pasando una función como valor de la prop onClick. React solo llamará a esta función después de un click. Olvidar `() =\u003e` y escribir `onClick={console.log('click')}` es un error común, y se ejecutaría cada vez que el componente se re-renderice.\n\nComo un siguiente paso, queremos que el componente Square “recuerde” que fue clickeado, y se rellene con una marca de “X”. Para “recordar” cosas, los componentes usan **estado**.\n\nLos componentes de React pueden tener estado estableciendo `this.state` en sus constructores. **`this.state`** debe ser considerado como privado para un componente de React en el que es definido. Vamos a almacenar el valor actual de un cuadrado en this.state, y cambiarlo cuando el cuadrado es clickeado.\n\nPrimero, vamos a agregar el constructor a la clase para inicializar el estado:\n\n```javascript\nclass Square extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n      value: null,\n    };\n  }\n\n  render() {\n    return (\n      \u003cbutton className=\"square\" onClick={() =\u003e console.log('click')}\u003e\n        {this.props.value}\n      \u003c/button\u003e\n    );\n  }\n}\n```\n\n\u003e En las [clases de JavaScript](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Classes), necesitas siempre llamar super cuando defines el constructor de una subclase. Todas las clases de componentes de React que tienen un constructor deben empezar con una llamada a super(props).\n\nAhora vamos a cambiar el método render de Square para mostrar el valor del estado actual cuando es clickeado:\n\n```javascript\nclass Square extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n      value: null,\n    };\n  }\n\n  render() {\n    return (\n      \u003cbutton\n        className=\"square\"\n        onClick={() =\u003e this.setState({value: 'X'})}\n      \u003e\n        {this.state.value}\n      \u003c/button\u003e\n    );\n  }\n}\n```\n\nLlamando a this.setState desde el manejador onClick en el método render de Square, decimos a React que re-renderice el cuadrado siempre que su \u003cbutton\u003e es clickeado. Luego de la actualización, el this.state.value del cuadrado será 'X', así que veremos X en el tablero de juego.\n\nCuando llamas `setState` en un componente, React actualiza automáticamente los componentes hijos dentro del mismo también.\n\n### Herramientas de desarrollo\n\nLa extensión de **React Devtools** para Chrome y Firefox te permite inspeccionar el árbol de componentes de React con tus herramientas de desarrollo del navegador.\n\nReact Devtools\nReact DevTools te permite revisar las props y el estado de tus componentes de React.\n\nDespués de instalar React DevTools, puedes hacer click derecho en cualquier elemento de la página, click en “Inspeccionar elemento” para abrir las herramientas de desarrollo, y la pestaña de React aparecerá como la última pestaña a la derecha. Usa “⚛️ Components” para inspeccionar el árbol de componentes.\n\n\n## Completando el juego\n\nAhora tenemos los bloques de construcción básicos para nuestro juego tic-tac-toe. Para completar el juego, necesitamos alternar colocando “X” y “O” en el tablero, y necesitas una forma de determinar el ganador.\n\n### Elevando el estado\n\nActualmente, cada componente Square mantiene el estado del juego. Para determinar un ganador, necesitamos mantener el valor de cada uno de los 9 cuadrados en un solo lugar.\n\nPodemos pensar que el tablero debería solo preguntar a cada cuadrado por su estado. Aunque este enfoque es posible en React, te incentivamos a que no lo uses porque el código se vuelve difícil de ententer, susceptible a errores, y difícil de refactorizar. En su lugar, el mejor enfoque es almacenar el estado del juego en el componente padre Board en vez de cada componente Square. El componente Board puede decirle a cada cuadrado que mostrar pasándole una prop tal cual hicimos cuando pasamos un número a cada cuadrado.\n\n**Para recopilar datos de múltiples hijos, o tener dos componentes hijos comunicados entre sí, necesitas declarar el estado compartido en su componente padre. El componente padre puede pasar el estado hacia los hijos usando props; esto mantiene los componentes hijos sincronizados entre ellos y con su componente padre.**\n\nElevar el estado al componente padre es común cuando componentes de React son refactorizados, vamos a tomar esta oportunidad para intentarlo.\n\nAñade un constructor al Board y establece el estado inicial de Board para contener un arreglo con 9 valores null. Estos 9 nulls corresponden a los 9 cuadrados:\n\n```javascript\nclass Board extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n      squares: Array(9).fill(null),\n    };\n  }\n\n  renderSquare(i) {\n    return \u003cSquare value={i} /\u003e;\n  }\n```\n\nCuando rellenemos el tablero luego, el arreglo this.state.squares se verá algo así:\n\n```javascript\n[\n  'O', null, 'X',\n  'X', 'X', 'O',\n  'O', null, null,\n]\n```\n\nEl método renderSquare del componente Board actualmente se ve así:\n\n```javascript\nrenderSquare(i) {\n    return \u003cSquare value={i} /\u003e;\n  }\n```\n\nAhora usaremos la prop pasando el mecanismo otra vez. Modificaremos el Board para instruir cada Square acerca de su valor actual ('X', 'O', ó null). Ya tenemos definido el arreglo squares en el constructor del Board, y modificaremos el método renderSquare para que lo lea desde allí:\n\n```javascript\n  renderSquare(i) {\n    return \u003cSquare value={this.state.squares[i]} /\u003e;\n  }\n```\n\nCada Square ahora recibirá una prop value que será `'X'`, `'O'`, ó `null` para cuadrados vacíos.\n\nLuego, necesitamos cambiar lo que sucede cuando un cuadrado es clickeado. El componente Board ahora mantiene qué cuadrados están rellenos. Necesitamos crear una forma para que el cuadrado actualice el estado del componente Board. ==Debido a que el estado es considerado privado al componente que lo define, no podemos actualizar el estado de Board directamente desde Square==.\n\nEn cambio, pasaremos una función como prop desde Board a Square y haremos que Square llame a esa función cuando un cuadrado sea clickeado. Cambiaremos el método `renderSquare` en Board a:\n\n```javascript\nrenderSquare(i) {\n    return (\n      \u003cSquare\n        value={this.state.squares[i]}\n        onClick={() =\u003e this.handleClick(i)}\n      /\u003e\n    );\n  }\n```\n\nAhora estamos pasando dos props desde Board a Square: value y onClick. la prop onClick es una función que Square puede llamar cuando sea clickeado. Haremos los siguientes cambios a Square:\n\n* Reemplazar `this.state.value` por `this.props.value` en el método render de Square\n* Reemplazar `this.setState()` por `this.props.onClick()` en el método render de Square\n* Eliminar el `constructor` de Square porque el componente ya no hace seguimiento del estado del juego\n\nLuego de estos cambios, el componente Square se ve algo así:\n\n```javascript\nclass Square extends React.Component {\n  render() {\n    return (\n      \u003cbutton\n        className=\"square\"\n        onClick={() =\u003e this.props.onClick()}\n      \u003e\n        {this.props.value}\n      \u003c/button\u003e\n    );\n  }\n}\n```\n\nCuando un cuadrado es clickeado, la función `onClick` provista por el componente Board es llamada. Aquí un repaso de cómo esto fue logrado:\n\n1. La prop `onClick` en el componente pre-construido del DOM `\u003cbutton\u003e` le dice a React para establecer un escuchador del evento click.\n\n2. Cuando el botón es clickeado, React llamará al manejador de evento onClick que está definido en el método render() de Square.\n\n3. Este manejador de evento llama a this.props.onClick(). la prop onClick del componente Square fue especificado por el componente Board.\n\n4. Debido a que el Board pasó onClick={() =\u003e this.handleClick(i)} a Square, el componente Square llama al handleClick(i) de Board cuando es clickeado.\n\n5. No tenemos definido el método `handleClick()` aun, así que nuestro código falla. Si haces click ahora verás una pantalla roja de error que dice algo como “this.handleClick is not a function” (this.handleClick no es una función).\n\nNota: \n\n\u003e El atributo `onClick` del elemento `\u003cbutton\u003e` del DOM tiene un significado especial para React porque es un componente pre-construido. Para componentes personalizados como Square, la nomenclatura la decides tú. Podríamos darle cualquier nombre al prop `onClick` de Square o al método `handleClick` de Board, y el código funcionaría de la misma forma. En React, sin embargo, es una convención usar los nombres `on[Evento]` para props que representan eventos y `handle[Evento]` para los métodos que manejan los eventos.\n\nCuando intentamos clickear un cuadrado, deberíamos obtener un error porque no hemos definido handleClick aun. Vamos ahora a agregar handleClick a la clase Board:\n\n```javascript\nhandleClick(i) {\n    const squares = this.state.squares.slice();\n    squares[i] = 'X';\n    this.setState({squares: squares});\n  }\n```\n\nLuego de estos cambios, podemos nuevamente clickear en los cuadrados para rellenarlos de la misma forma que lo hicimos antes. Sin embargo, ahora el estado está almacenado en el componente Board en lugar de cada componente Square. Cuando el estado del Board cambia, los componentes Square se re-renderiza automáticamente. Mantener el estado de todos los cuadrados en el componente Board nos permitirá determinar el ganador en el futuro.\n\nDebido a que el componente Square ahora no mantiene estado, los componentes Square reciben valores del componente Board e informan al mismo cuando son clickeados. ==En términos de React, los componentes Square ahora son **componentes controlados**. El componente Board tiene control completo sobre ellos==.\n\nNotar cómo en `handleClick`, llamamos `.slice()` para crear una copia del array de squares para modificarlo en vez de modificar el array existente. Ahora explicaremos porqué crear una copia del array squares en la siguiente sección.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgitfrandu4%2Freact-tutorial-tic-tac-toe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgitfrandu4%2Freact-tutorial-tic-tac-toe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgitfrandu4%2Freact-tutorial-tic-tac-toe/lists"}